blob: c7377140772e784cee93dbc344e1e1ae6a5acbb8 [file] [log] [blame]
hyatt@apple.com5388e672013-09-06 20:54:47 +00001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003-2013 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "RenderBlockFlow.h"
26
weinig@apple.com611b9292013-10-20 22:57:54 +000027#include "Editor.h"
bjonesbe@adobe.com67478092013-09-09 22:18:17 +000028#include "FloatingObjects.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000029#include "Frame.h"
zalan@apple.come36543a2014-07-29 01:45:54 +000030#include "FrameSelection.h"
darin@apple.com15708b12014-03-16 16:38:58 +000031#include "HTMLElement.h"
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000032#include "HitTestLocation.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000033#include "InlineTextBox.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000034#include "LayoutRepainter.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000035#include "RenderCombineText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000036#include "RenderFlowThread.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000037#include "RenderInline.h"
akling@apple.comf3028052013-11-04 08:46:06 +000038#include "RenderIterator.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000039#include "RenderLayer.h"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000040#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000041#include "RenderMarquee.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000042#include "RenderMultiColumnFlowThread.h"
43#include "RenderMultiColumnSet.h"
mihnea@adobe.combe79cf12013-10-17 09:02:19 +000044#include "RenderNamedFlowFragment.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000045#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000046#include "RenderText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000047#include "RenderView.h"
antti@apple.com940f5872013-10-24 20:31:11 +000048#include "SimpleLineLayoutFunctions.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000049#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000050#include "VisiblePosition.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000051
hyatt@apple.com5388e672013-09-06 20:54:47 +000052namespace WebCore {
53
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000054bool RenderBlock::s_canPropagateFloatIntoSibling = false;
55
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000056struct SameSizeAsMarginInfo {
57 uint32_t bitfields : 16;
58 LayoutUnit margins[2];
59};
60
61COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000062COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000063
64// Our MarginInfo state used when laying out block children.
weinig@apple.com12840dc2013-10-22 23:59:08 +000065RenderBlockFlow::MarginInfo::MarginInfo(RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000066 : m_atBeforeSideOfBlock(true)
67 , m_atAfterSideOfBlock(false)
68 , m_hasMarginBeforeQuirk(false)
69 , m_hasMarginAfterQuirk(false)
70 , m_determinedMarginBeforeQuirk(false)
71 , m_discardMargin(false)
72{
akling@apple.com827be9c2013-10-29 02:58:43 +000073 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000074 ASSERT(block.isRenderView() || block.parent());
75 m_canCollapseWithChildren = !block.isRenderView() && !block.isRoot() && !block.isOutOfFlowPositioned()
76 && !block.isFloating() && !block.isTableCell() && !block.hasOverflowClip() && !block.isInlineBlockOrInlineTable()
77 && !block.isRenderFlowThread() && !block.isWritingModeRoot() && !block.parent()->isFlexibleBox()
akling@apple.com827be9c2013-10-29 02:58:43 +000078 && blockStyle.hasAutoColumnCount() && blockStyle.hasAutoColumnWidth() && !blockStyle.columnSpan();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000079
akling@apple.com827be9c2013-10-29 02:58:43 +000080 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000081
82 // If any height other than auto is specified in CSS, then we don't collapse our bottom
83 // margins with our children's margins. To do otherwise would be to risk odd visual
84 // effects when the children overflow out of the parent block and yet still collapse
85 // with it. We also don't collapse if we have any bottom border/padding.
86 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000087 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000088
weinig@apple.com12840dc2013-10-22 23:59:08 +000089 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000090
weinig@apple.com12840dc2013-10-22 23:59:08 +000091 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000092
weinig@apple.com12840dc2013-10-22 23:59:08 +000093 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
94 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000095}
96
akling@apple.com8f40c5b2013-10-27 22:54:07 +000097RenderBlockFlow::RenderBlockFlow(Element& element, PassRef<RenderStyle> style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +000098 : RenderBlock(element, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +000099#if ENABLE(IOS_TEXT_AUTOSIZING)
100 , m_widthForTextAutosizing(-1)
101 , m_lineCountForTextAutosizing(NOT_SET)
102#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000103{
weinig@apple.com611b9292013-10-20 22:57:54 +0000104 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000105}
106
akling@apple.com8f40c5b2013-10-27 22:54:07 +0000107RenderBlockFlow::RenderBlockFlow(Document& document, PassRef<RenderStyle> style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +0000108 : RenderBlock(document, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000109#if ENABLE(IOS_TEXT_AUTOSIZING)
110 , m_widthForTextAutosizing(-1)
111 , m_lineCountForTextAutosizing(NOT_SET)
112#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000113{
weinig@apple.com611b9292013-10-20 22:57:54 +0000114 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000115}
116
117RenderBlockFlow::~RenderBlockFlow()
118{
119}
120
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000121void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000122{
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000123 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
124 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000125 setChildrenInline(false); // Do this to avoid wrapping inline children that are just going to move into the flow thread.
abucur@adobe.com99757c62014-07-31 13:43:52 +0000126 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000127 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000128 flowThread->populate(); // Called after the flow thread is inserted so that we are reachable by the flow thread.
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000129 setMultiColumnFlowThread(flowThread);
130}
131
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000132void RenderBlockFlow::destroyMultiColumnFlowThread()
133{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000134 multiColumnFlowThread()->evacuateAndDestroy();
135 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000136}
137
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000138void RenderBlockFlow::insertedIntoTree()
139{
140 RenderBlock::insertedIntoTree();
141 createRenderNamedFlowFragmentIfNeeded();
142}
143
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000144void RenderBlockFlow::willBeDestroyed()
145{
weinig@apple.com611b9292013-10-20 22:57:54 +0000146 // Mark as being destroyed to avoid trouble with merges in removeChild().
147 m_beingDestroyed = true;
148
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000149 if (renderNamedFlowFragment())
150 setRenderNamedFlowFragment(0);
weinig@apple.com611b9292013-10-20 22:57:54 +0000151
weinig@apple.com611b9292013-10-20 22:57:54 +0000152 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
153 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
154 destroyLeftoverChildren();
155
156 // Destroy our continuation before anything other than anonymous children.
157 // The reason we don't destroy it before anonymous children is that they may
158 // have continuations of their own that are anonymous children of our continuation.
159 RenderBoxModelObject* continuation = this->continuation();
160 if (continuation) {
161 continuation->destroy();
162 setContinuation(0);
163 }
164
165 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000166 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000167 // We can't wait for RenderBox::destroy to clear the selection,
168 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000169 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000170 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000171
172 // If we are an anonymous block, then our line boxes might have children
173 // that will outlast this block. In the non-anonymous block case those
174 // children will be destroyed by the time we return from this function.
175 if (isAnonymousBlock()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000176 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000177 while (auto childBox = box->firstChild())
178 childBox->removeFromParent();
179 }
180 }
181 } else if (parent())
182 parent()->dirtyLinesFromChangedChild(this);
183 }
184
akling@apple.com31dd4f42013-10-30 22:27:59 +0000185 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000186
dbates@webkit.org34f59002014-05-20 20:34:35 +0000187 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000188
189 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
190 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000191}
192
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000193void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000194{
195 if (m_floatingObjects)
196 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
197
198 HashSet<RenderBox*> oldIntrudingFloatSet;
199 if (!childrenInline() && m_floatingObjects) {
200 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000201 auto end = floatingObjectSet.end();
202 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
203 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000204 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000205 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000206 }
207 }
208
209 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
210 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000211 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000212 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000213 if (!oldIntrudingFloatSet.isEmpty())
214 markAllDescendantsWithFloatsForLayout();
215 return;
216 }
217
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000218 RendererToFloatInfoMap floatMap;
219
220 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000221 if (childrenInline())
222 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
223 else
224 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000225 }
226
227 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
228 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
229 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000230 if (!parent() || !parent()->isRenderBlockFlow())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000231 return;
232
233 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
234 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
235 // to avoid floats.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000236 RenderBlockFlow* parentBlock = toRenderBlockFlow(parent());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000237 bool parentHasFloats = false;
238 RenderObject* prev = previousSibling();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000239 while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlockFlow() || toRenderBlockFlow(prev)->avoidsFloats())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000240 if (prev->isFloating())
241 parentHasFloats = true;
242 prev = prev->previousSibling();
243 }
244
robert@webkit.org97037ef2013-11-20 19:26:10 +0000245 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
246 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000247 LayoutUnit logicalTopOffset = logicalTop();
robert@webkit.org97037ef2013-11-20 19:26:10 +0000248 if (parentHasFloats || (parentBlock->lowestFloatLogicalBottom() > logicalTopOffset && prev && toRenderBlockFlow(prev)->isSelfCollapsingBlock()))
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000249 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
250
251 LayoutUnit logicalLeftOffset = 0;
252 if (prev)
253 logicalTopOffset -= toRenderBox(prev)->logicalTop();
254 else {
255 prev = parentBlock;
256 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
257 }
258
259 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000260 RenderBlockFlow* block = toRenderBlockFlow(prev);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000261 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
262 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
263
264 if (childrenInline()) {
265 LayoutUnit changeLogicalTop = LayoutUnit::max();
266 LayoutUnit changeLogicalBottom = LayoutUnit::min();
267 if (m_floatingObjects) {
268 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000269 auto end = floatingObjectSet.end();
270 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000271 FloatingObject* floatingObject = it->get();
272 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject->renderer());
273 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000274 if (oldFloatingObject) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000275 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
276 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000277 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000278 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000279 } else {
280 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000281 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
282 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000283 }
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000284 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
285 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000286 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000287 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
288 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000289 }
290 }
291
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000292 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
293 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
294 oldFloatingObject->originatingLine()->markDirty();
295 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000296 } else {
297 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000298 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000299 }
300 }
301 }
302
darin@apple.com7cad7042013-09-24 05:53:55 +0000303 auto end = floatMap.end();
304 for (auto it = floatMap.begin(); it != end; ++it) {
305 FloatingObject* floatingObject = it->value.get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000306 if (!floatingObject->isDescendant()) {
307 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000308 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000309 }
310 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000311
312 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
313 } else if (!oldIntrudingFloatSet.isEmpty()) {
314 // If there are previously intruding floats that no longer intrude, then children with floats
315 // should also get layout because they might need their floating object lists cleared.
316 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
317 markAllDescendantsWithFloatsForLayout();
318 else {
319 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000320 auto end = floatingObjectSet.end();
321 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
322 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000323 if (!oldIntrudingFloatSet.isEmpty())
324 markAllDescendantsWithFloatsForLayout();
325 }
326 }
327}
328
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000329void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
330{
331 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
332 // The min/max intrinsic widths calculated really tell how much space elements need when
333 // laid out inside the columns. In order to eventually end up with the desired column width,
334 // we need to convert them to values pertaining to the multicol container.
335 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
336 LayoutUnit columnWidth;
337 LayoutUnit colGap = columnGap();
338 LayoutUnit gapExtra = (columnCount - 1) * colGap;
339 if (style().hasAutoColumnWidth())
340 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
341 else {
342 columnWidth = style().columnWidth();
343 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
344 }
345 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
346 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
347 // performing a layout pass, but this is not an appropriate time or place for layout. The
348 // good news is that if height is unconstrained and there are no explicit breaks, the
349 // resolved column-count really should be 1.
350 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
351 }
352}
353
354void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
355{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000356 if (childrenInline())
357 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
358 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000359 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
360
361 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
362
363 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
364
365 if (!style().autoWrap() && childrenInline()) {
366 // A horizontal marquee with inline children has no minimum width.
367 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
368 minLogicalWidth = 0;
369 }
370
371 if (isTableCell()) {
372 Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth();
373 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
374 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
375 }
376
377 int scrollbarWidth = instrinsicScrollbarLogicalWidth();
378 maxLogicalWidth += scrollbarWidth;
379 minLogicalWidth += scrollbarWidth;
380}
381
382bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
383{
384 bool changed = recomputeLogicalWidth();
385
386 LayoutUnit oldColumnWidth = computedColumnWidth();
387 computeColumnCountAndWidth();
388
389 return changed || oldColumnWidth != computedColumnWidth();
390}
391
392LayoutUnit RenderBlockFlow::columnGap() const
393{
394 if (style().hasNormalColumnGap())
395 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
396 return style().columnGap();
397}
398
399void RenderBlockFlow::computeColumnCountAndWidth()
400{
401 // Calculate our column width and column count.
402 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
403 unsigned desiredColumnCount = 1;
404 LayoutUnit desiredColumnWidth = contentLogicalWidth();
405
406 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
407 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
408 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
409 return;
410 }
411
412 LayoutUnit availWidth = desiredColumnWidth;
413 LayoutUnit colGap = columnGap();
414 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
415 int colCount = std::max<int>(1, style().columnCount());
416
417 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
418 desiredColumnCount = colCount;
419 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
420 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
421 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
422 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
423 } else {
424 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
425 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
426 }
427 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
428}
429
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000430void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
431{
432 ASSERT(needsLayout());
433
434 if (!relayoutChildren && simplifiedLayout())
435 return;
436
437 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
438
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000439 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000440 relayoutChildren = true;
441
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000442 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000443
444 LayoutUnit previousHeight = logicalHeight();
445 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
446 // for consistency with other render classes?
447 setLogicalHeight(0);
448
449 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000450 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000451
akling@apple.com827be9c2013-10-29 02:58:43 +0000452 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000453 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000454
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000455 preparePaginationBeforeBlockLayout(relayoutChildren);
abucur@adobe.com0e81bc72013-10-22 14:50:37 +0000456 if (!relayoutChildren)
457 relayoutChildren = namedFlowFragmentNeedsUpdate();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000458
459 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
460 // our current maximal positive and negative margins. These values are used when we
461 // are collapsed with adjacent blocks, so for example, if you have block A and B
462 // collapsing together, then you'd take the maximal positive margin from both A and B
463 // and subtract it from the maximal negative margin from both A and B to get the
464 // true collapsed margin. This algorithm is recursive, so when we finish layout()
465 // our block knows its current maximal positive/negative values.
466 //
467 // Start out by setting our margin values to our current margins. Table cells have
468 // no margins, so we don't fill in the values for table cells.
469 bool isCell = isTableCell();
470 if (!isCell) {
471 initMaxMarginValues();
472
akling@apple.com827be9c2013-10-29 02:58:43 +0000473 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
474 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000475 setPaginationStrut(0);
476 }
477
478 LayoutUnit repaintLogicalTop = 0;
479 LayoutUnit repaintLogicalBottom = 0;
480 LayoutUnit maxFloatLogicalBottom = 0;
481 if (!firstChild() && !isAnonymousBlock())
482 setChildrenInline(true);
483 if (childrenInline())
484 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
485 else
486 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
487
488 // Expand our intrinsic height to encompass floats.
489 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
490 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
491 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
492
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000493 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000494 ASSERT(!shouldBreakAtLineToAvoidWidow());
495 return;
496 }
497
498 // Calculate our new height.
499 LayoutUnit oldHeight = logicalHeight();
500 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
501
502 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
503 // This ensures the size information is correctly computed for the last auto-height region receiving content.
504 if (isRenderFlowThread())
505 toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge);
506
507 updateLogicalHeight();
508 LayoutUnit newHeight = logicalHeight();
509 if (oldHeight != newHeight) {
510 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
511 // One of our children's floats may have become an overhanging float for us. We need to look for it.
akling@apple.com525dae62014-01-03 20:22:09 +0000512 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
513 if (blockFlow.isFloatingOrOutOfFlowPositioned())
514 continue;
515 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
516 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000517 }
518 }
519 }
520
521 bool heightChanged = (previousHeight != newHeight);
522 if (heightChanged)
523 relayoutChildren = true;
524
525 layoutPositionedObjects(relayoutChildren || isRoot());
526
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000527 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
528 computeOverflow(oldClientAfterEdge);
529
530 statePusher.pop();
531
532 fitBorderToLinesIfNeeded();
533
534 if (view().layoutState()->m_pageLogicalHeight)
535 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
536
537 updateLayerTransform();
538
539 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
540 // we overflow or not.
541 updateScrollInfoAfterLayout();
542
543 // FIXME: This repaint logic should be moved into a separate helper function!
544 // Repaint with our new bounds if they are different from our old bounds.
545 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000546 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000547 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
548 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
549 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
550 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
551 if (hasOverflowClip()) {
552 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
553 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
554 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000555 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
556 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000557 }
558
559 LayoutRect repaintRect;
560 if (isHorizontalWritingMode())
561 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
562 else
563 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
564
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000565 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
566
567 if (hasOverflowClip()) {
568 // Adjust repaint rect for scroll offset
569 repaintRect.move(-scrolledContentOffset());
570
571 // Don't allow this rect to spill out of our overflow box.
572 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
573 }
574
575 // Make sure the rect is still non-empty after intersecting for overflow above
576 if (!repaintRect.isEmpty()) {
577 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
578 if (hasReflection())
579 repaintRectangle(reflectedRect(repaintRect));
580 }
581 }
582
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000583 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000584}
585
586void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
587{
588 dirtyForLayoutFromPercentageHeightDescendants();
589
590 LayoutUnit beforeEdge = borderAndPaddingBefore();
591 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
592
593 setLogicalHeight(beforeEdge);
594
595 // Lay out our hypothetical grid line as though it occurs at the top of the block.
596 if (view().layoutState()->lineGrid() == this)
597 layoutLineGridBox();
598
599 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000600 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000601
602 // Fieldsets need to find their legend and position it inside the border of the object.
603 // The legend then gets skipped during normal layout. The same is true for ruby text.
604 // It doesn't get included in the normal layout process but is instead skipped.
605 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
606
607 LayoutUnit previousFloatLogicalBottom = 0;
608 maxFloatLogicalBottom = 0;
609
610 RenderBox* next = firstChildBox();
611
612 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000613 RenderBox& child = *next;
614 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000615
weinig@apple.com12840dc2013-10-22 23:59:08 +0000616 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000617 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
618
619 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
620
weinig@apple.com12840dc2013-10-22 23:59:08 +0000621 if (child.isOutOfFlowPositioned()) {
622 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000623 adjustPositionedBlock(child, marginInfo);
624 continue;
625 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000626 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000627 insertFloatingObject(child);
628 adjustFloatingBlock(marginInfo);
629 continue;
630 }
631
632 // Lay out the child.
633 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
634 }
635
636 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
637 // determining the correct collapsed bottom margin information.
638 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
639}
640
antti@apple.com940f5872013-10-24 20:31:11 +0000641void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
642{
antti@apple.com42fb53d2013-10-25 02:33:11 +0000643 if (m_lineLayoutPath == UndeterminedPath)
644 m_lineLayoutPath = SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath;
645
646 if (m_lineLayoutPath == SimpleLinesPath) {
antti@apple.com940f5872013-10-24 20:31:11 +0000647 deleteLineBoxesBeforeSimpleLineLayout();
648 layoutSimpleLines(repaintLogicalTop, repaintLogicalBottom);
649 return;
650 }
651
antti@apple.comfea51992013-10-28 13:39:23 +0000652 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000653 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
654}
655
weinig@apple.com12840dc2013-10-22 23:59:08 +0000656void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000657{
658 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
659 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
660
661 // The child is a normal flow object. Compute the margins we will use for collapsing now.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000662 child.computeAndSetBlockDirectionMargins(this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000663
664 // Try to guess our correct logical top position. In most cases this guess will
665 // be correct. Only if we're wrong (when we compute the real logical top position)
666 // will we have to potentially relayout.
667 LayoutUnit estimateWithoutPagination;
668 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
669
670 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000671 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000672 LayoutUnit oldLogicalTop = logicalTopForChild(child);
673
674#if !ASSERT_DISABLED
675 LayoutSize oldLayoutDelta = view().layoutDelta();
676#endif
677 // Go ahead and position the child as though it didn't collapse with the top.
678 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
679 estimateRegionRangeForBoxChild(child);
680
weinig@apple.com12840dc2013-10-22 23:59:08 +0000681 RenderBlockFlow* childBlockFlow = child.isRenderBlockFlow() ? toRenderBlockFlow(&child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000682 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000683 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000684 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000685 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
686 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
687 // very large elements. If it does the comparison with oldLogicalTop might yield a
688 // false negative as adding and removing margins, borders etc from a saturated number
689 // might yield incorrect results. If this is the case always mark for layout.
690 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000691 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000692 // If an element might be affected by the presence of floats, then always mark it for
693 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000694 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000695 if (fb > logicalTopEstimate)
696 markDescendantsWithFloats = true;
697 }
698
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000699 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000700 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000701 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000702 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000703 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000704 }
705
weinig@apple.com12840dc2013-10-22 23:59:08 +0000706 if (!child.needsLayout())
707 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000708
weinig@apple.com12840dc2013-10-22 23:59:08 +0000709 bool childHadLayout = child.everHadLayout();
710 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000711 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000712 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000713
714 // Cache if we are at the top of the block right now.
715 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
716
717 // Now determine the correct ypos based off examination of collapsing margin
718 // values.
719 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
720
721 // Now check for clear.
722 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
723
724 bool paginated = view().layoutState()->isPaginated();
725 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000726 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000727
728 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
729
730 // Now we have a final top position. See if it really does end up being different from our estimate.
731 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
732 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000733 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
734 if (child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000735 // The child's width depends on the line width.
736 // When the child shifts to clear an item, its width can
737 // change (because it has more available line width).
738 // So go ahead and mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000739 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000740 }
741
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000742 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000743 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000744 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000745 if (!child.needsLayout())
746 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000747 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000748 }
749
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000750 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000751 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000752
753 // In case our guess was wrong, relayout the child.
754 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000755
756 // We are no longer at the top of the block if we encounter a non-empty child.
757 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000758 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000759 marginInfo.setAtBeforeSideOfBlock(false);
760
761 // Now place the child in the correct left position
762 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
763
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000764 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000765 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000766 if (mustSeparateMarginAfterForChild(child)) {
767 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
768 marginInfo.clearMargin();
769 }
770 // If the child has overhanging floats that intrude into following siblings (or possibly out
771 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000772 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000773 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000774
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000775 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000776 if (childOffset.width() || childOffset.height()) {
777 view().addLayoutDelta(childOffset);
778
779 // If the child moved, we have to repaint it as well as any floating/positioned
780 // descendants. An exception is if we need a layout. In this case, we know we're going to
781 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000782 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
783 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000784 }
785
weinig@apple.com12840dc2013-10-22 23:59:08 +0000786 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
787 child.repaint();
788 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000789 }
790
791 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000792 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
793 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000794 // Check for an after page/column break.
795 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
796 if (newHeight != height())
797 setLogicalHeight(newHeight);
798 }
799
800 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
801}
802
weinig@apple.com12840dc2013-10-22 23:59:08 +0000803void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000804{
805 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000806 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000807
808 LayoutUnit logicalTop = logicalHeight();
809 updateStaticInlinePositionForChild(child, logicalTop);
810
811 if (!marginInfo.canCollapseWithMarginBefore()) {
812 // Positioned blocks don't collapse margins, so add the margin provided by
813 // the container now. The child's own margin is added later when calculating its logical top.
814 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
815 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
816 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
817 }
818
weinig@apple.com12840dc2013-10-22 23:59:08 +0000819 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000820 if (childLayer->staticBlockPosition() != logicalTop) {
821 childLayer->setStaticBlockPosition(logicalTop);
822 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000823 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000824 }
825}
826
robert@webkit.org97037ef2013-11-20 19:26:10 +0000827LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
828{
829 ASSERT(isSelfCollapsingBlock());
830 RenderBlockFlow* parentBlock = toRenderBlockFlow(parent());
831 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
832 return marginValuesForChild(*this).positiveMarginBefore();
833 return LayoutUnit();
834}
835
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000836void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
837{
838 LayoutUnit startPosition = borderStart() + paddingStart();
839 if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
840 startPosition -= verticalScrollbarWidth();
841 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
842
843 // Add in our start margin.
844 LayoutUnit childMarginStart = marginStartForChild(child);
845 LayoutUnit newPosition = startPosition + childMarginStart;
846
847 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
848 // to shift over as necessary to dodge any floats that might get in the way.
849 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
850 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
851
852 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
853}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000854
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000855void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
856{
857 // The float should be positioned taking into account the bottom margin
858 // of the previous flow. We add that margin into the height, get the
859 // float positioned properly, and then subtract the margin out of the
860 // height again. In the case of self-collapsing blocks, we always just
861 // use the top margins, since the self-collapsing block collapsed its
862 // own bottom margin into its top margin.
863 //
864 // Note also that the previous flow may collapse its margin into the top of
865 // our block. If this is the case, then we do not add the margin in to our
866 // height when computing the position of the float. This condition can be tested
867 // for by simply calling canCollapseWithMarginBefore. See
868 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
869 // an example of this scenario.
870 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
871 setLogicalHeight(logicalHeight() + marginOffset);
872 positionNewFloats();
873 setLogicalHeight(logicalHeight() - marginOffset);
874}
875
weinig@apple.com12840dc2013-10-22 23:59:08 +0000876void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop)
877{
akling@apple.com827be9c2013-10-29 02:58:43 +0000878 if (child.style().isOriginalDisplayInlineType())
weinig@apple.com12840dc2013-10-22 23:59:08 +0000879 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
880 else
881 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
882}
883
884void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
885{
886 if (flowThreadContainingBlock()) {
887 // Shift the inline position to exclude the region offset.
888 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
889 }
890 child.layer()->setStaticInlinePosition(inlinePosition);
891}
892
893RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000894{
895 LayoutUnit childBeforePositive = 0;
896 LayoutUnit childBeforeNegative = 0;
897 LayoutUnit childAfterPositive = 0;
898 LayoutUnit childAfterNegative = 0;
899
900 LayoutUnit beforeMargin = 0;
901 LayoutUnit afterMargin = 0;
902
weinig@apple.com12840dc2013-10-22 23:59:08 +0000903 RenderBlockFlow* childRenderBlock = child.isRenderBlockFlow() ? toRenderBlockFlow(&child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000904
905 // If the child has the same directionality as we do, then we can just return its
906 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000907 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000908 if (childRenderBlock) {
909 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
910 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
911 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
912 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
913 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000914 beforeMargin = child.marginBefore();
915 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000916 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000917 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000918 // The child has a different directionality. If the child is parallel, then it's just
919 // flipped relative to us. We can use the margins for the opposite edges.
920 if (childRenderBlock) {
921 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
922 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
923 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
924 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
925 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000926 beforeMargin = child.marginAfter();
927 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000928 }
929 } else {
930 // The child is perpendicular to us, which means its margins don't collapse but are on the
931 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
932 beforeMargin = marginBeforeForChild(child);
933 afterMargin = marginAfterForChild(child);
934 }
935
936 // Resolve uncollapsing margins into their positive/negative buckets.
937 if (beforeMargin) {
938 if (beforeMargin > 0)
939 childBeforePositive = beforeMargin;
940 else
941 childBeforeNegative = -beforeMargin;
942 }
943 if (afterMargin) {
944 if (afterMargin > 0)
945 childAfterPositive = afterMargin;
946 else
947 childAfterNegative = -afterMargin;
948 }
949
950 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
951}
952
weinig@apple.com12840dc2013-10-22 23:59:08 +0000953LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000954{
955 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
956 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +0000957 bool childIsSelfCollapsing = child.isSelfCollapsingBlock();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000958
959 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
960 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
961
962 // Get the four margin values for the child and cache them.
963 const MarginValues childMargins = marginValuesForChild(child);
964
965 // Get our max pos and neg top margins.
966 LayoutUnit posTop = childMargins.positiveMarginBefore();
967 LayoutUnit negTop = childMargins.negativeMarginBefore();
968
969 // For self-collapsing blocks, collapse our bottom margins into our
970 // top to get new posTop and negTop values.
971 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000972 posTop = std::max(posTop, childMargins.positiveMarginAfter());
973 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000974 }
975
976 // See if the top margin is quirky. We only care if this child has
977 // margins that will collapse with us.
978 bool topQuirk = hasMarginBeforeQuirk(child);
979
980 if (marginInfo.canCollapseWithMarginBefore()) {
981 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
982 // This child is collapsing with the top of the
983 // block. If it has larger margin values, then we need to update
984 // our own maximal values.
985 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +0000986 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000987
988 // The minute any of the margins involved isn't a quirk, don't
989 // collapse it away, even if the margin is smaller (www.webreference.com
990 // has an example of this, a <dt> with 0.8em author-specified inside
991 // a <dl> inside a <td>.
992 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
993 setHasMarginBeforeQuirk(false);
994 marginInfo.setDeterminedMarginBeforeQuirk(true);
995 }
996
997 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
998 // We have no top margin and our top child has a quirky margin.
999 // We will pick up this quirky margin and pass it through.
1000 // This deals with the <td><div><p> case.
1001 // Don't do this for a block that split two inlines though. You do
1002 // still apply margins in this case.
1003 setHasMarginBeforeQuirk(true);
1004 } else
1005 // The before margin of the container will also discard all the margins it is collapsing with.
1006 setMustDiscardMarginBefore();
1007 }
1008
1009 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1010 if (childDiscardMarginBefore) {
1011 marginInfo.setDiscardMargin(true);
1012 marginInfo.clearMargin();
1013 }
1014
1015 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1016 marginInfo.setHasMarginBeforeQuirk(topQuirk);
1017
1018 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1019 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001020
1021 LayoutUnit clearanceForSelfCollapsingBlock;
1022 RenderObject* prev = child.previousSibling();
1023 // 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
1024 // of the float. Since we want to collapse the child's top margin with the self-collapsing block's top and bottom margins we need to adjust our parent's height to match the
1025 // margin top of the self-collapsing block. If the resulting collapsed margin leaves the child still intruding into the float then we will want to clear it.
1026 if (!marginInfo.canCollapseWithMarginBefore() && prev && prev->isRenderBlockFlow() && toRenderBlockFlow(prev)->isSelfCollapsingBlock()) {
1027 clearanceForSelfCollapsingBlock = toRenderBlockFlow(prev)->marginOffsetForSelfCollapsingBlock();
1028 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1029 }
1030
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001031 if (childIsSelfCollapsing) {
1032 // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
1033 // Also, the child's top position equals the logical height of the container.
1034 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1035 // This child has no height. We need to compute our
1036 // position before we collapse the child's margins together,
1037 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001038 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1039 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001040 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1041
1042 // Now collapse the child's margins together, which means examining our
1043 // bottom margin values as well.
1044 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1045 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1046
1047 if (!marginInfo.canCollapseWithMarginBefore())
1048 // We need to make sure that the position of the self-collapsing block
1049 // is correct, since it could have overflowing content
1050 // that needs to be positioned correctly (e.g., a block that
1051 // had a specified height of 0 but that actually had subcontent).
1052 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1053 }
1054 } else {
1055 if (mustSeparateMarginBeforeForChild(child)) {
1056 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1057 // If we are at the before side of the block and we collapse, ignore the computed margin
1058 // and just add the child margin to the container height. This will correctly position
1059 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001060 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001061 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
1062 logicalTop = logicalHeight();
1063 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1064 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1065 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1066 // We're collapsing with a previous sibling's margins and not
1067 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001068 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001069 logicalTop = logicalHeight();
1070 }
1071
1072 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1073
1074 if (!marginInfo.discardMargin()) {
1075 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1076 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1077 } else
1078 marginInfo.clearMargin();
1079
1080 if (marginInfo.margin())
1081 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
1082 }
1083
1084 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1085 // collapsed into the page edge.
1086 LayoutState* layoutState = view().layoutState();
1087 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1088 && hasNextPage(beforeCollapseLogicalTop)) {
1089 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001090 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001091 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1092 }
1093
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001094 if (prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001095 // If |child| is a self-collapsing block it may have collapsed into a previous sibling and although it hasn't reduced the height of the parent yet
1096 // any floats from the parent will now overhang.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001097 RenderBlockFlow& block = toRenderBlockFlow(*prev);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001098 LayoutUnit oldLogicalHeight = logicalHeight();
1099 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001100 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001101 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001102 setLogicalHeight(oldLogicalHeight);
1103
1104 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1105 // into the margin area of the self-collapsing block then the float it clears is now intruding into |child|. Layout again so that we can look for
1106 // floats in the parent that overhang |child|'s new logical top.
1107 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
1108 if (logicalTopIntrudesIntoFloat && containsFloats() && !child.avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1109 child.setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001110 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001111
1112 return logicalTop;
1113}
1114
weinig@apple.com12840dc2013-10-22 23:59:08 +00001115LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001116{
1117 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1118 if (!heightIncrease)
1119 return yPos;
1120
weinig@apple.com12840dc2013-10-22 23:59:08 +00001121 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001122 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1123
1124 // For self-collapsing blocks that clear, they can still collapse their
1125 // margins with following siblings. Reset the current margins to represent
1126 // the self-collapsing block's margins only.
1127 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001128 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001129 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001130 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1131 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001132 } else
1133 marginInfo.clearMargin();
1134 marginInfo.setDiscardMargin(childDiscardMargin);
1135
1136 // CSS2.1 states:
1137 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1138 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1139 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1140 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1141 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001142 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001143 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1144 wouldCollapseMarginsWithParent = false;
1145 }
1146 if (wouldCollapseMarginsWithParent)
1147 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1148
robert@webkit.org97037ef2013-11-20 19:26:10 +00001149 // For now set the border-top of |child| flush with the bottom border-edge of the float so it can layout any floating or positioned children of
1150 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1151 // adjust the height of the parent to |child|'s margin top (which if it is positive sits up 'inside' the float it's clearing) so that all three
1152 // margins can collapse at the correct vertical position.
1153 // Per CSS2.1 we need to ensure that any negative margin-top clears |child| beyond the bottom border-edge of the float so that the top border edge of the child
1154 // (i.e. its clearance) is at a position that satisfies the equation: "the amount of clearance is set so that clearance + margin-top = [height of float],
1155 // i.e., clearance = [height of float] - margin-top".
1156 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001157 } else
1158 // Increase our height by the amount we had to clear.
1159 setLogicalHeight(logicalHeight() + heightIncrease);
1160
1161 if (marginInfo.canCollapseWithMarginBefore()) {
1162 // We can no longer collapse with the top of the block since a clear
1163 // occurred. The empty blocks collapse into the cleared block.
1164 // FIXME: This isn't quite correct. Need clarification for what to do
1165 // if the height the cleared block is offset by is smaller than the
1166 // margins involved.
1167 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1168 marginInfo.setAtBeforeSideOfBlock(false);
1169
1170 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
akling@apple.com827be9c2013-10-29 02:58:43 +00001171 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001172 }
1173
robert@webkit.org97037ef2013-11-20 19:26:10 +00001174 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001175}
1176
weinig@apple.com12840dc2013-10-22 23:59:08 +00001177void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001178{
1179 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1180 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1181 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001182 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001183 return;
1184
1185 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1186 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001187 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001188 positiveMarginBefore = 0;
1189 negativeMarginBefore = 0;
1190 discardMarginBefore = true;
1191 return;
1192 }
1193
1194 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001195 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1196 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001197
weinig@apple.com12840dc2013-10-22 23:59:08 +00001198 if (!child.isRenderBlockFlow())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001199 return;
1200
weinig@apple.com12840dc2013-10-22 23:59:08 +00001201 RenderBlockFlow& childBlock = toRenderBlockFlow(child);
1202 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001203 return;
1204
weinig@apple.com12840dc2013-10-22 23:59:08 +00001205 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001206 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1207 return;
1208
weinig@apple.com12840dc2013-10-22 23:59:08 +00001209 RenderBox* grandchildBox = childBlock.firstChildBox();
1210 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001211 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1212 break;
1213 }
1214
1215 // Give up if there is clearance on the box, since it probably won't collapse into us.
akling@apple.com827be9c2013-10-29 02:58:43 +00001216 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001217 return;
1218
1219 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1220 if (grandchildBox->needsLayout()) {
1221 grandchildBox->computeAndSetBlockDirectionMargins(this);
1222 if (grandchildBox->isRenderBlock()) {
1223 RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
akling@apple.com827be9c2013-10-29 02:58:43 +00001224 grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1225 grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001226 }
1227 }
1228
1229 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001230 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001231}
1232
weinig@apple.com12840dc2013-10-22 23:59:08 +00001233LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001234{
1235 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1236 // relayout if there are intruding floats.
1237 LayoutUnit logicalTopEstimate = logicalHeight();
1238 if (!marginInfo.canCollapseWithMarginBefore()) {
1239 LayoutUnit positiveMarginBefore = 0;
1240 LayoutUnit negativeMarginBefore = 0;
1241 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001242 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001243 // Try to do a basic estimation of how the collapse is going to go.
1244 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1245 } else {
1246 // Use the cached collapsed margin values from a previous layout. Most of the time they
1247 // will be right.
1248 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001249 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1250 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001251 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1252 }
1253
1254 // Collapse the result with our current margins.
1255 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001256 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001257 }
1258
1259 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1260 // page.
1261 LayoutState* layoutState = view().layoutState();
1262 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1263 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001264 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001265
1266 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1267
1268 estimateWithoutPagination = logicalTopEstimate;
1269
1270 if (layoutState->isPaginated()) {
1271 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1272 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1273
1274 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1275 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1276
weinig@apple.com12840dc2013-10-22 23:59:08 +00001277 if (!child.selfNeedsLayout() && child.isRenderBlock())
1278 logicalTopEstimate += toRenderBlock(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001279 }
1280
1281 return logicalTopEstimate;
1282}
1283
1284void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1285{
1286 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1287 // 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.
1288 // Don't update the max margin values because we won't need them anyway.
1289 if (marginInfo.discardMargin()) {
1290 setMustDiscardMarginAfter();
1291 return;
1292 }
1293
1294 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1295 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001296 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001297
1298 if (!marginInfo.hasMarginAfterQuirk())
1299 setHasMarginAfterQuirk(false);
1300
1301 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1302 // We have no bottom margin and our last child has a quirky margin.
1303 // We will pick up this quirky margin and pass it through.
1304 // This deals with the <td><div><p> case.
1305 setHasMarginAfterQuirk(true);
1306 }
1307}
1308
1309void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1310{
1311 marginInfo.setAtAfterSideOfBlock(true);
1312
robert@webkit.org97037ef2013-11-20 19:26:10 +00001313 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1314 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1315 // to perform now is at the child's margin-top - so adjust our height to that position.
1316 RenderObject* lastBlock = lastChild();
1317 if (lastBlock && lastBlock->isRenderBlockFlow() && toRenderBlockFlow(lastBlock)->isSelfCollapsingBlock())
1318 setLogicalHeight(logicalHeight() - toRenderBlockFlow(lastBlock)->marginOffsetForSelfCollapsingBlock());
1319
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001320 // If we can't collapse with children then go ahead and add in the bottom margin.
1321 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1322 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1323 setLogicalHeight(logicalHeight() + marginInfo.margin());
1324
1325 // Now add in our bottom border/padding.
1326 setLogicalHeight(logicalHeight() + afterSide);
1327
1328 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1329 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001330 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001331
1332 // Update our bottom collapsed margin info.
1333 setCollapsedBottomMargin(marginInfo);
1334}
1335
1336void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1337{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001338 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001339 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001340 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001341 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001342 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001343
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001344 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1345 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001346}
1347
1348void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1349{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001350 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001351 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001352 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001353 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001354 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001355
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001356 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1357 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001358}
1359
1360void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1361{
akling@apple.com827be9c2013-10-29 02:58:43 +00001362 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001363 ASSERT(value);
1364 return;
1365 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001366
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001367 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001368 if (!value)
1369 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001370 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001371 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001372
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001373 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001374}
1375
1376void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1377{
akling@apple.com827be9c2013-10-29 02:58:43 +00001378 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001379 ASSERT(value);
1380 return;
1381 }
1382
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001383 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001384 if (!value)
1385 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001386 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001387 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001388
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001389 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001390}
1391
1392bool RenderBlockFlow::mustDiscardMarginBefore() const
1393{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001394 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001395}
1396
1397bool RenderBlockFlow::mustDiscardMarginAfter() const
1398{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001399 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001400}
1401
weinig@apple.com12840dc2013-10-22 23:59:08 +00001402bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001403{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001404 ASSERT(!child.selfNeedsLayout());
1405 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001406 return child.isRenderBlockFlow() ? toRenderBlockFlow(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001407 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001408 return child.isRenderBlockFlow() ? toRenderBlockFlow(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001409
1410 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1411 // In case the boxes are perpendicular we assume the property is not specified.
1412 return false;
1413}
1414
weinig@apple.com12840dc2013-10-22 23:59:08 +00001415bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001416{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001417 ASSERT(!child.selfNeedsLayout());
1418 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001419 return child.isRenderBlockFlow() ? toRenderBlockFlow(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001420 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001421 return child.isRenderBlockFlow() ? toRenderBlockFlow(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001422
1423 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1424 return false;
1425}
1426
weinig@apple.com12840dc2013-10-22 23:59:08 +00001427bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001428{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001429 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001430 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001431 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001432 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001433 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001434 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001435
1436 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1437 return false;
1438}
1439
weinig@apple.com12840dc2013-10-22 23:59:08 +00001440bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001441{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001442 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001443 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001444 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001445 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001446 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001447 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001448
1449 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1450 return false;
1451}
1452
weinig@apple.com12840dc2013-10-22 23:59:08 +00001453static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001454{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001455 RenderBlock* curr = child.containingBlock();
1456 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001457 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001458 return true;
1459 if (curr->isFloatingOrOutOfFlowPositioned())
1460 return false;
1461 curr = curr->containingBlock();
1462 }
1463 return true;
1464}
1465
weinig@apple.com12840dc2013-10-22 23:59:08 +00001466LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001467{
1468 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001469 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001470 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001471 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001472 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001473 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001474 bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
1475 || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001476 || (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001477 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001478 if (checkColumnBreaks) {
1479 if (isInsideMulticolFlowThread)
1480 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001481 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001482 if (checkRegionBreaks) {
1483 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001484 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001485 return logicalOffset + offsetBreakAdjustment;
1486 }
1487 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1488 }
1489 return logicalOffset;
1490}
1491
weinig@apple.com12840dc2013-10-22 23:59:08 +00001492LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001493{
1494 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001495 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001496 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001497 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001498 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001499 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001500 bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
1501 || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001502 || (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001503 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1504 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1505
1506 // So our margin doesn't participate in the next collapsing steps.
1507 marginInfo.clearMargin();
1508
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001509 if (checkColumnBreaks) {
1510 if (isInsideMulticolFlowThread)
1511 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001512 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001513 if (checkRegionBreaks) {
1514 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001515 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001516 return logicalOffset + marginOffset + offsetBreakAdjustment;
1517 }
1518 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1519 }
1520 return logicalOffset;
1521}
1522
weinig@apple.com12840dc2013-10-22 23:59:08 +00001523LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001524{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001525 RenderBlock* childRenderBlock = child.isRenderBlock() ? toRenderBlock(&child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001526
1527 if (estimateWithoutPagination != logicalTopAfterClear) {
1528 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1529 // position.
1530 setLogicalHeight(logicalTopAfterClear);
1531 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1532
weinig@apple.com12840dc2013-10-22 23:59:08 +00001533 if (child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001534 // The child's width depends on the line width.
1535 // When the child shifts to clear an item, its width can
1536 // change (because it has more available line width).
1537 // So go ahead and mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001538 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001539 }
1540
1541 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001542 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001543 toRenderBlockFlow(childRenderBlock)->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001544 if (!child.needsLayout())
1545 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001546 }
1547
1548 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001549 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001550 }
1551
1552 LayoutUnit oldTop = logicalTopAfterClear;
1553
1554 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1555 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1556
1557 if (pageLogicalHeightForOffset(result)) {
1558 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001559 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001560 if (spaceShortage > 0) {
1561 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1562 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1563 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1564 // This should be improved, though, because here we just pretend that the child is
1565 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1566 // where there's no child content, border or padding. In other words, we risk stretching more
1567 // than necessary.
1568 setPageBreak(result, spaceShortage);
1569 }
1570 }
1571
1572 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1573 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1574 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1575
1576 LayoutUnit paginationStrut = 0;
1577 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1578 if (unsplittableAdjustmentDelta)
1579 paginationStrut = unsplittableAdjustmentDelta;
1580 else if (childRenderBlock && childRenderBlock->paginationStrut())
1581 paginationStrut = childRenderBlock->paginationStrut();
1582
1583 if (paginationStrut) {
1584 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1585 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1586 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1587 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1588 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1589 // and pushes to the next page anyway, so not too concerned about it.
1590 setPaginationStrut(result + paginationStrut);
1591 if (childRenderBlock)
1592 childRenderBlock->setPaginationStrut(0);
1593 } else
1594 result += paginationStrut;
1595 }
1596
1597 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
1598 setLogicalHeight(logicalHeight() + (result - oldTop));
1599
1600 // Return the final adjusted logical top.
1601 return result;
1602}
1603
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001604static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
1605{
1606 // We may require a certain minimum number of lines per page in order to satisfy
1607 // orphans and widows, and that may affect the minimum page height.
andersca@apple.com86298632013-11-10 19:32:33 +00001608 unsigned lineCount = std::max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001609 if (lineCount > 1) {
1610 RootInlineBox* line = lastLine;
1611 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1612 line = line->prevRootBox();
1613
1614 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1615 // adjustLinePositionForPagination() for more details.
1616 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001617 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001618 }
1619 return lineBottom - lineTop;
1620}
1621
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001622void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001623{
1624 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1625 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1626 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1627 // of the first column.
1628 //
1629 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1630 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1631 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1632 // for overflow to occur), and then cache visible overflow for each column rect.
1633 //
1634 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1635 // content that paints in a previous column (and content that paints in the following column).
1636 //
1637 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1638 // at least make positive leading work in typical cases.
1639 //
1640 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1641 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1642 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001643 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001644 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001645 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1646 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001647 LayoutUnit lineHeight = logicalBottom - logicalOffset;
akling@apple.com827be9c2013-10-29 02:58:43 +00001648 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(&style(), lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001649 logicalOffset += delta;
1650 lineBox->setPaginationStrut(0);
1651 lineBox->setIsFirstAfterPageBreak(false);
1652 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1653 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1654 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1655 // still going to add a strut, so that the visible overflow fits on a single page.
1656 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
1657 || !hasNextPage(logicalOffset))
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001658 // FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page.
1659 // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001660 return;
1661 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001662 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001663
1664 int lineIndex = lineCount(lineBox);
1665 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001666 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001667 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001668 setDidBreakAtLineToAvoidWidow();
1669 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001670 // If we have a non-uniform page height, then we have to shift further possibly.
1671 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1672 return;
1673 if (lineHeight > pageLogicalHeight) {
1674 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001675 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001676 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001677 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1678 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001679 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001680 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1681 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001682 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001683 && !isOutOfFlowPositioned() && !isTableCell())
andersca@apple.com86298632013-11-10 19:32:33 +00001684 setPaginationStrut(remainingLogicalHeight + std::max<LayoutUnit>(0, logicalOffset));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001685 else {
1686 delta += remainingLogicalHeight;
1687 lineBox->setPaginationStrut(remainingLogicalHeight);
1688 lineBox->setIsFirstAfterPageBreak(true);
1689 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001690 } else if (remainingLogicalHeight == pageLogicalHeight) {
1691 // We're at the very top of a page or column.
1692 if (lineBox != firstRootBox())
1693 lineBox->setIsFirstAfterPageBreak(true);
1694 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1695 setPageBreak(logicalOffset, lineHeight);
1696 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001697}
1698
1699void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1700{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001701 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001702 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1703 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001704}
1705
abucur@adobe.comfc497132013-10-04 08:49:21 +00001706void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1707{
1708 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001709 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001710 return;
1711
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001712 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001713}
1714
1715void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1716{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001717 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001718 return;
1719
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001720 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001721}
1722
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001723void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1724{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001725 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001726 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001727 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001728
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001729 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001730}
1731
1732bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1733{
1734 if (!shouldBreakAtLineToAvoidWidow())
1735 return false;
1736
1737 statePusher.pop();
1738 setEverHadLayout(true);
1739 layoutBlock(false);
1740 return true;
1741}
1742
weinig@apple.com31324fd2013-10-28 19:22:51 +00001743bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1744{
1745 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1746
1747 RenderFlowThread* flowThread = flowThreadContainingBlock();
1748 if (!flowThread)
1749 return true; // Printing and multi-column both make new pages to accommodate content.
1750
1751 // See if we're in the last region.
1752 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001753 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001754 if (!region)
1755 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001756
weinig@apple.com31324fd2013-10-28 19:22:51 +00001757 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001758 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001759 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001760
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001761 RenderRegion* startRegion = nullptr;
1762 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001763 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001764 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001765}
1766
1767LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1768{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001769 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001770 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001771
1772 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001773 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1774 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1775 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1776 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1777 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1778 || !hasNextPage(logicalOffset))
1779 return logicalOffset;
1780 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1781 if (remainingLogicalHeight < childLogicalHeight) {
1782 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1783 return logicalOffset;
1784 return logicalOffset + remainingLogicalHeight;
1785 }
1786 return logicalOffset;
1787}
1788
1789bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1790{
1791 bool checkRegion = false;
1792 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1793 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1794 if (minimumLogicalHeight <= pageLogicalHeight)
1795 return true;
1796 if (!hasNextPage(logicalOffset + adjustment))
1797 return false;
1798 adjustment += pageLogicalHeight;
1799 checkRegion = true;
1800 }
1801 return !checkRegion;
1802}
1803
1804void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1805{
1806 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1807 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1808}
1809
1810void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1811{
1812 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1813 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001814}
1815
1816LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1817{
1818 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1819 if (!pageLogicalHeight)
1820 return logicalOffset;
1821
1822 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1823 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1824 if (pageBoundaryRule == ExcludePageBoundary)
1825 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1826 return logicalOffset + remainingLogicalHeight;
1827}
1828
1829LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1830{
1831 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1832 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1833
1834 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1835 RenderFlowThread* flowThread = flowThreadContainingBlock();
1836 if (!flowThread) {
1837 LayoutUnit pageLogicalHeight = view().layoutState()->pageLogicalHeight();
1838 if (!pageLogicalHeight)
1839 return 0;
1840 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
1841 }
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001842 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001843}
1844
1845LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1846{
1847 RenderFlowThread* flowThread = flowThreadContainingBlock();
1848 if (!flowThread)
1849 return view().layoutState()->m_pageLogicalHeight;
1850 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1851}
1852
1853LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1854{
1855 offset += offsetFromLogicalTopOfFirstPage();
1856
1857 RenderFlowThread* flowThread = flowThreadContainingBlock();
1858 if (!flowThread) {
1859 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1860 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1861 if (pageBoundaryRule == IncludePageBoundary) {
1862 // If includeBoundaryPoint is true the line exactly on the top edge of a
1863 // column will act as being part of the previous column.
1864 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1865 }
1866 return remainingHeight;
1867 }
1868
1869 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1870}
1871
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001872LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1873{
1874 // This method is required because regions do not fragment monolithic elements but instead
1875 // they let them overflow the region they flow in. This behaviour is different from the
1876 // multicol/printing implementations, which have not yet been updated to correctly handle
1877 // monolithic elements.
1878 // As a result, for the moment, this method will only be used for regions, the multicol and
1879 // printing implementations will stick to the existing behaviour until their fragmentation
1880 // implementation is updated to match the regions implementation.
1881 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1882 return logicalHeightForChild(child);
1883
1884 // For unsplittable elements, this method will just return the height of the element that
1885 // fits into the current region, without the height of the part that overflows the region.
1886 // This is done for all regions, except the last one because in that case, the logical
1887 // height of the flow thread needs to also
1888 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1889 return logicalHeightForChild(child);
1890
1891 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1892 // the entire unsplittable child because any following children will not be moved to the next page
1893 // so they will need to be laid out below the current unsplittable child.
1894 LayoutUnit childLogicalTop = logicalTopForChild(child);
1895 if (!hasNextPage(childLogicalTop))
1896 return logicalHeightForChild(child);
1897
1898 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1899 return std::min(child.logicalHeight(), remainingLogicalHeight);
1900}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001901
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001902void RenderBlockFlow::layoutLineGridBox()
1903{
akling@apple.com827be9c2013-10-29 02:58:43 +00001904 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001905 setLineGridBox(0);
1906 return;
1907 }
1908
1909 setLineGridBox(0);
1910
akling@apple.com1aa97b02013-10-31 21:59:49 +00001911 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001912 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1913 lineGridBox->setConstructed();
1914 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1915 VerticalPositionCache verticalPositionCache;
1916 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1917
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00001918 setLineGridBox(WTF::move(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001919
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001920 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1921 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1922 // to this grid.
1923}
1924
weinig@apple.com12840dc2013-10-22 23:59:08 +00001925bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001926{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001927 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001928}
1929
1930void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1931{
1932 RenderBlock::styleDidChange(diff, oldStyle);
1933
1934 // After our style changed, if we lose our ability to propagate floats into next sibling
1935 // blocks, then we need to find the top most parent containing that overhanging float and
1936 // then mark its descendants with floats for layout and clear all floats from its next
1937 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1938 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1939 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
1940 RenderBlockFlow* parentBlock = this;
1941 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001942
weinig@apple.comc77041e2013-12-14 18:05:45 +00001943 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
1944 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00001945 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00001946 if (ancestor.hasOverhangingFloats()) {
akling@apple.comf3028052013-11-04 08:46:06 +00001947 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
1948 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00001949 if (ancestor.hasOverhangingFloat(renderer)) {
1950 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00001951 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001952 }
1953 }
1954 }
1955 }
1956
1957 parentBlock->markAllDescendantsWithFloatsForLayout();
1958 parentBlock->markSiblingsWithFloatsForLayout();
1959 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00001960
akling@apple.com8f40c5b2013-10-27 22:54:07 +00001961 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00001962 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00001963
antti@apple.com9e891c82014-05-22 06:12:34 +00001964 if (diff >= StyleDifferenceRepaint) {
1965 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
1966 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
1967 invalidateLineLayoutPath();
1968 }
1969
hyatt@apple.comfdb12812014-06-23 18:56:52 +00001970 if (multiColumnFlowThread())
1971 updateStylesForColumnChildren();
1972}
1973
1974void RenderBlockFlow::updateStylesForColumnChildren()
1975{
1976 for (auto child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
1977 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001978}
1979
akling@apple.combdae43242013-10-25 12:00:20 +00001980void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001981{
akling@apple.com827be9c2013-10-29 02:58:43 +00001982 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001983 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
1984
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00001985 if (oldStyle) {
1986 EPosition oldPosition = oldStyle->position();
1987 EPosition newPosition = newStyle.position();
1988
1989 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
1990 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
1991 markAllDescendantsWithFloatsForLayout();
1992
1993 // If this block is inside a multicol and is moving from in-flow positioning to out-of-flow positioning,
1994 // remove its info (such as lines-to-region mapping) from the flowthread because it won't be able to do it later.
1995 // The flowthread will no longer be in its containing block chain and, as such, flowThreadContainingBlock will return null.
1996 if (RenderFlowThread* flowThread = flowThreadContainingBlock(SkipFlowThreadCache)) {
1997 if (flowThread->isRenderMultiColumnFlowThread() && !isOutOfFlowPositioned() && (newPosition == AbsolutePosition || newPosition == FixedPosition))
1998 flowThread->removeFlowChildInfo(this);
1999 }
2000 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002001 }
2002
2003 RenderBlock::styleWillChange(diff, newStyle);
2004}
2005
antti@apple.coma2c7f242013-10-22 22:37:25 +00002006void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002007{
2008 if (containsFloats())
2009 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002010
antti@apple.comfea51992013-10-28 13:39:23 +00002011 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002012 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002013 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002014 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002015 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002016
antti@apple.coma2c7f242013-10-22 22:37:25 +00002017 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002018}
2019
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002020void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002021{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002022 // When a portion of the render tree is being detached, anonymous blocks
2023 // will be combined as their children are deleted. In this process, the
2024 // anonymous block later in the tree is merged into the one preceeding it.
2025 // It can happen that the later block (this) contains floats that the
2026 // previous block (toBlockFlow) did not contain, and thus are not in the
2027 // floating objects list for toBlockFlow. This can result in toBlockFlow
2028 // containing floats that are not in it's floating objects list, but are in
2029 // the floating objects lists of siblings and parents. This can cause
2030 // problems when the float itself is deleted, since the deletion code
2031 // assumes that if a float is not in it's containing block's floating
2032 // objects list, it isn't in any floating objects list. In order to
2033 // preserve this condition (removing it has serious performance
2034 // implications), we need to copy the floating objects from the old block
2035 // (this) to the new block (toBlockFlow). The float's metrics will likely
2036 // all be wrong, but since toBlockFlow is already marked for layout, this
2037 // will get fixed before anything gets displayed.
2038 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2039 if (m_floatingObjects) {
2040 if (!toBlockFlow->m_floatingObjects)
2041 toBlockFlow->createFloatingObjects();
2042
2043 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2044 auto end = fromFloatingObjectSet.end();
2045
2046 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2047 FloatingObject* floatingObject = it->get();
2048
2049 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002050 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002051 continue;
2052
2053 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2054 }
2055 }
2056}
2057
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002058void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert)
2059{
2060 RenderBlockFlow* toBlockFlow = toRenderBlockFlow(toBlock);
2061 moveAllChildrenTo(toBlockFlow, fullRemoveInsert);
2062 moveFloatsTo(toBlockFlow);
2063}
2064
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002065void RenderBlockFlow::addOverflowFromFloats()
2066{
2067 if (!m_floatingObjects)
2068 return;
2069
2070 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2071 auto end = floatingObjectSet.end();
2072 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2073 FloatingObject* r = it->get();
2074 if (r->isDescendant())
2075 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
2076 }
2077}
2078
2079void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2080{
2081 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2082
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002083 if (!multiColumnFlowThread() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002084 addOverflowFromFloats();
2085}
2086
2087void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2088{
2089 // Repaint any overhanging floats (if we know we're the one to paint them).
2090 // Otherwise, bail out.
2091 if (!hasOverhangingFloats())
2092 return;
2093
2094 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2095 // in this block. Better yet would be to push extra state for the containers of other floats.
2096 LayoutStateDisabler layoutStateDisabler(&view());
2097 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2098 auto end = floatingObjectSet.end();
2099 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2100 FloatingObject* floatingObject = it->get();
2101 // Only repaint the object if it is overhanging, is not in its own layer, and
2102 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2103 // condition is replaced with being a descendant of us.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002104 if (logicalBottomForFloat(floatingObject) > logicalHeight()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002105 && !floatingObject->renderer().hasSelfPaintingLayer()
2106 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
2107 floatingObject->renderer().repaint();
2108 floatingObject->renderer().repaintOverhangingFloats(false);
2109 }
2110 }
2111}
2112
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002113void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002114{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002115 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002116
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002117 if (!multiColumnFlowThread() || paintInfo.context->paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002118 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002119
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002120 // Iterate over our children and paint the column rules as needed.
2121 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2122 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2123 columnSet.paintColumnRules(paintInfo, childPoint);
2124 }
2125}
2126
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002127void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2128{
2129 if (!m_floatingObjects)
2130 return;
2131
2132 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2133 auto end = floatingObjectSet.end();
2134 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2135 FloatingObject* r = it->get();
2136 // Only paint the object if our m_shouldPaint flag is set.
2137 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
2138 PaintInfo currentPaintInfo(paintInfo);
2139 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2140 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
2141 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2142 r->renderer().paint(currentPaintInfo, childPoint);
2143 if (!preservePhase) {
2144 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2145 r->renderer().paint(currentPaintInfo, childPoint);
2146 currentPaintInfo.phase = PaintPhaseFloat;
2147 r->renderer().paint(currentPaintInfo, childPoint);
2148 currentPaintInfo.phase = PaintPhaseForeground;
2149 r->renderer().paint(currentPaintInfo, childPoint);
2150 currentPaintInfo.phase = PaintPhaseOutline;
2151 r->renderer().paint(currentPaintInfo, childPoint);
2152 }
2153 }
2154 }
2155}
2156
weinig@apple.com12840dc2013-10-22 23:59:08 +00002157void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002158{
2159 if (m_floatingObjects) {
2160 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2161 auto end = floatingObjectSet.end();
2162 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2163 FloatingObject* floatingObject = it->get();
2164 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2165 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
2166 floatingObject->renderer().width(), floatingObject->renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002167 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002168 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
zalan@apple.com376339c2014-08-28 04:24:31 +00002169 paintInfo->context->clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002170 }
2171 }
2172}
2173
2174void RenderBlockFlow::createFloatingObjects()
2175{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002176 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002177}
2178
2179void RenderBlockFlow::removeFloatingObjects()
2180{
2181 if (!m_floatingObjects)
2182 return;
2183
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002184 markSiblingsWithFloatsForLayout();
2185
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002186 m_floatingObjects->clear();
2187}
2188
weinig@apple.com12840dc2013-10-22 23:59:08 +00002189FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002190{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002191 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002192
2193 // Create the list of special objects if we don't aleady have one
2194 if (!m_floatingObjects)
2195 createFloatingObjects();
2196 else {
2197 // Don't insert the floatingObject again if it's already in the list
2198 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002199 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002200 if (it != floatingObjectSet.end())
2201 return it->get();
2202 }
2203
2204 // Create the special floatingObject entry & append it to the list
2205
weinig@apple.com12840dc2013-10-22 23:59:08 +00002206 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002207
2208 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
2209 // Just go ahead and lay out the float.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002210 bool isChildRenderBlock = floatBox.isRenderBlock();
2211 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2212 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002213
2214 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2215 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002216 floatBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002217 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002218 floatBox.updateLogicalWidth();
2219 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002220 }
2221
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002222 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002223
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00002224 return m_floatingObjects->add(WTF::move(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002225}
2226
weinig@apple.com12840dc2013-10-22 23:59:08 +00002227void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002228{
2229 if (m_floatingObjects) {
2230 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002231 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002232 if (it != floatingObjectSet.end()) {
2233 FloatingObject* floatingObject = it->get();
2234 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002235 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2236 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002237
2238 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2239 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2240 logicalBottom = LayoutUnit::max();
2241 else {
2242 // Special-case zero- and less-than-zero-height floats: those don't touch
2243 // the line that they're on, but it still needs to be dirtied. This is
2244 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002245 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002246 }
2247 if (floatingObject->originatingLine()) {
2248 if (!selfNeedsLayout()) {
2249 ASSERT(&floatingObject->originatingLine()->renderer() == this);
2250 floatingObject->originatingLine()->markDirty();
2251 }
2252#if !ASSERT_DISABLED
2253 floatingObject->setOriginatingLine(0);
2254#endif
2255 }
2256 markLinesDirtyInBlockRange(0, logicalBottom);
2257 }
2258 m_floatingObjects->remove(floatingObject);
2259 }
2260 }
2261}
2262
2263void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2264{
2265 if (!containsFloats())
2266 return;
2267
2268 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2269 FloatingObject* curr = floatingObjectSet.last().get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002270 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002271 m_floatingObjects->remove(curr);
2272 if (floatingObjectSet.isEmpty())
2273 break;
2274 curr = floatingObjectSet.last().get();
2275 }
2276}
2277
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002278LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2279{
2280 LayoutUnit offset = fixedOffset;
2281 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2282 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2283 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2284}
2285
2286LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2287{
2288 LayoutUnit offset = fixedOffset;
2289 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2290 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2291 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2292}
2293
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002294LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002295{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002296 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002297 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002298 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002299
andersca@apple.com86298632013-11-10 19:32:33 +00002300 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002301
2302 LayoutUnit floatLogicalLeft;
2303
2304 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002305 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2306
2307 if (isInitialLetter) {
2308 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2309 if (letterClearance > 0) {
2310 logicalTopOffset += letterClearance;
2311 setLogicalHeight(logicalHeight() + letterClearance);
2312 }
2313 }
2314
akling@apple.com827be9c2013-10-29 02:58:43 +00002315 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002316 LayoutUnit heightRemainingLeft = 1;
2317 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002318 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2319 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002320 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002321 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002322 if (insideFlowThread) {
2323 // Have to re-evaluate all of our offsets, since they may have changed.
2324 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2325 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002326 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002327 }
2328 }
andersca@apple.com86298632013-11-10 19:32:33 +00002329 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002330 } else {
2331 LayoutUnit heightRemainingLeft = 1;
2332 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002333 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2334 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002335 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002336 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002337 if (insideFlowThread) {
2338 // Have to re-evaluate all of our offsets, since they may have changed.
2339 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2340 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002341 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002342 }
2343 }
2344 // Use the original width of the float here, since the local variable
2345 // |floatLogicalWidth| was capped to the available line width. See
2346 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002347 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002348 }
2349
hyatt@apple.com87515262014-09-04 21:20:12 +00002350 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002351 const RenderStyle& style = firstLineStyle();
2352 const FontMetrics& fontMetrics = style.fontMetrics();
2353 if (fontMetrics.hasCapHeight()) {
2354 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2355 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2356
2357 // Make an adjustment to align with the cap height of a theoretical block line.
2358 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2359 logicalTopOffset += adjustment;
2360
2361 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2362 // positive for raised and negative for sunken).
2363 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2364
2365 // If we're sunken, the float needs to shift down but lines still need to avoid it. In order to do that we increase the float's margin.
2366 if (dropHeightDelta < 0) {
2367 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2368 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2369 }
2370
2371 // If we're raised, then we actually have to grow the height of the block, since the lines have to be pushed down as though we're placing
2372 // empty lines beside the first letter.
2373 if (dropHeightDelta > 0)
2374 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2375 }
2376 }
2377
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002378 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2379}
2380
2381bool RenderBlockFlow::positionNewFloats()
2382{
2383 if (!m_floatingObjects)
2384 return false;
2385
2386 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2387 if (floatingObjectSet.isEmpty())
2388 return false;
2389
2390 // If all floats have already been positioned, then we have no work to do.
2391 if (floatingObjectSet.last()->isPlaced())
2392 return false;
2393
2394 // Move backwards through our floating object list until we find a float that has
2395 // already been positioned. Then we'll be able to move forward, positioning all of
2396 // the new floats that need it.
2397 auto it = floatingObjectSet.end();
2398 --it; // Go to last item.
2399 auto begin = floatingObjectSet.begin();
2400 FloatingObject* lastPlacedFloatingObject = 0;
2401 while (it != begin) {
2402 --it;
2403 if ((*it)->isPlaced()) {
2404 lastPlacedFloatingObject = it->get();
2405 ++it;
2406 break;
2407 }
2408 }
2409
2410 LayoutUnit logicalTop = logicalHeight();
2411
2412 // The float cannot start above the top position of the last positioned float.
2413 if (lastPlacedFloatingObject)
andersca@apple.com86298632013-11-10 19:32:33 +00002414 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002415
2416 auto end = floatingObjectSet.end();
2417 // Now walk through the set of unpositioned floats and place them.
2418 for (; it != end; ++it) {
2419 FloatingObject* floatingObject = it->get();
2420 // The containing block is responsible for positioning floats, so if we have floats in our
2421 // list that come from somewhere else, do not attempt to position them.
2422 if (floatingObject->renderer().containingBlock() != this)
2423 continue;
2424
weinig@apple.com12840dc2013-10-22 23:59:08 +00002425 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002426
akling@apple.com827be9c2013-10-29 02:58:43 +00002427 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002428
weinig@apple.com12840dc2013-10-22 23:59:08 +00002429 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002430
akling@apple.com827be9c2013-10-29 02:58:43 +00002431 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002432 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002433 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002434 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002435
2436 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2437
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002438 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002439
2440 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2441 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2442
2443 estimateRegionRangeForBoxChild(childBox);
2444
2445 LayoutState* layoutState = view().layoutState();
2446 bool isPaginated = layoutState->isPaginated();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002447 if (isPaginated && !childBox.needsLayout())
2448 childBox.markForPaginationRelayoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002449
weinig@apple.com12840dc2013-10-22 23:59:08 +00002450 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002451
2452 if (isPaginated) {
2453 // If we are unsplittable and don't fit, then we need to move down.
2454 // We include our margins as part of the unsplittable area.
2455 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2456
2457 // See if we have a pagination strut that is making us move down further.
2458 // Note that an unsplittable child can't also have a pagination strut, so this is
2459 // exclusive with the case above.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002460 RenderBlock* childBlock = childBox.isRenderBlock() ? toRenderBlock(&childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002461 if (childBlock && childBlock->paginationStrut()) {
2462 newLogicalTop += childBlock->paginationStrut();
2463 childBlock->setPaginationStrut(0);
2464 }
2465
2466 if (newLogicalTop != floatLogicalLocation.y()) {
2467 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
2468
2469 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002470 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002471
2472 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2473 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2474
2475 if (childBlock)
2476 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002477 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002478 }
2479
2480 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002481 childBox.setNeedsLayout(MarkOnlyThis);
2482 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002483 }
2484 }
2485
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002486 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002487
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002488 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002489
2490 m_floatingObjects->addPlacedObject(floatingObject);
2491
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002492#if ENABLE(CSS_SHAPES)
2493 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002494 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002495#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002496 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002497 if (childBox.checkForRepaintDuringLayout())
2498 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002499 }
2500 return true;
2501}
2502
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002503void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002504{
2505 positionNewFloats();
2506 // set y position
2507 LayoutUnit newY = 0;
2508 switch (clear) {
2509 case CLEFT:
2510 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2511 break;
2512 case CRIGHT:
2513 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2514 break;
2515 case CBOTH:
2516 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002517 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002518 default:
2519 break;
2520 }
2521 if (height() < newY)
2522 setLogicalHeight(newY);
2523}
2524
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002525LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002526{
2527 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002528 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002529
2530 return fixedOffset;
2531}
2532
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002533LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002534{
2535 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002536 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002537
2538 return fixedOffset;
2539}
2540
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002541LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002542{
2543 if (!m_floatingObjects)
2544 return logicalHeight;
2545
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002546 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2547}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002548
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002549LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2550{
2551 if (!m_floatingObjects)
2552 return logicalHeight;
2553
2554 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002555}
2556
2557LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2558{
2559 if (!m_floatingObjects)
2560 return 0;
2561 LayoutUnit lowestFloatBottom = 0;
2562 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2563 auto end = floatingObjectSet.end();
2564 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2565 FloatingObject* floatingObject = it->get();
2566 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
andersca@apple.com86298632013-11-10 19:32:33 +00002567 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002568 }
2569 return lowestFloatBottom;
2570}
2571
hyatt@apple.com87515262014-09-04 21:20:12 +00002572LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2573{
2574 if (!m_floatingObjects)
2575 return 0;
2576 LayoutUnit lowestFloatBottom = 0;
2577 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2578 auto end = floatingObjectSet.end();
2579 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2580 FloatingObject* floatingObject = it->get();
2581 if (floatingObject->isPlaced() && floatingObject->renderer().style().styleType() == FIRST_LETTER && floatingObject->renderer().style().initialLetterDrop() > 0)
2582 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2583 }
2584 return lowestFloatBottom;
2585}
2586
weinig@apple.com12840dc2013-10-22 23:59:08 +00002587LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002588{
2589 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002590 if (child.hasOverflowClip() || !child.containsFloats() || child.isRoot() || child.isWritingModeRoot() || child.isRenderFlowThread() || child.isRenderRegion())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002591 return 0;
2592
weinig@apple.com12840dc2013-10-22 23:59:08 +00002593 LayoutUnit childLogicalTop = child.logicalTop();
2594 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002595 LayoutUnit lowestFloatLogicalBottom = 0;
2596
2597 // Floats that will remain the child's responsibility to paint should factor into its
2598 // overflow.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002599 auto childEnd = child.m_floatingObjects->set().end();
2600 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002601 FloatingObject* floatingObject = childIt->get();
andersca@apple.com86298632013-11-10 19:32:33 +00002602 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002603 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002604 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002605
2606 if (logicalBottom > logicalHeight()) {
2607 // If the object is not in the list, we add it now.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002608 if (!containsFloat(floatingObject->renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002609 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2610 bool shouldPaint = false;
2611
2612 // The nearest enclosing layer always paints the float (so that zindex and stacking
2613 // behaves properly). We always want to propagate the desire to paint the float as
2614 // far out as we can, to the outermost block that overlaps the float, stopping only
2615 // if we hit a self-painting layer boundary.
2616 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2617 floatingObject->setShouldPaint(false);
2618 shouldPaint = true;
2619 }
2620 // We create the floating object list lazily.
2621 if (!m_floatingObjects)
2622 createFloatingObjects();
2623
2624 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2625 }
2626 } else {
2627 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
weinig@apple.com12840dc2013-10-22 23:59:08 +00002628 && floatingObject->renderer().isDescendantOf(&child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002629 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2630 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2631 // layer.
2632 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2633 // it should paint.
2634 floatingObject->setShouldPaint(true);
2635 }
2636
2637 // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the
2638 // child now.
2639 if (floatingObject->isDescendant())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002640 child.addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002641 }
2642 }
2643 return lowestFloatLogicalBottom;
2644}
2645
weinig@apple.com12840dc2013-10-22 23:59:08 +00002646bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002647{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002648 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002649 return false;
2650
2651 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002652 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002653 if (it == floatingObjectSet.end())
2654 return false;
2655
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002656 return logicalBottomForFloat(it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002657}
2658
2659void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
2660{
2661 ASSERT(!avoidsFloats());
2662
2663 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2664 if (!prev->m_floatingObjects)
2665 return;
2666
2667 logicalLeftOffset += marginLogicalLeft();
2668
2669 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2670 auto prevEnd = prevSet.end();
2671 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2672 FloatingObject* floatingObject = prevIt->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002673 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002674 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2675 // We create the floating object list lazily.
2676 if (!m_floatingObjects)
2677 createFloatingObjects();
2678
2679 // Applying the child's margin makes no sense in the case where the child was passed in.
2680 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2681 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2682 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2683 // will get applied twice.
2684 LayoutSize offset = isHorizontalWritingMode()
2685 ? LayoutSize(logicalLeftOffset - (prev != parent() ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2686 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != parent() ? prev->marginTop() : LayoutUnit()));
2687
2688 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2689 }
2690 }
2691 }
2692}
2693
2694void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2695{
2696 if (!everHadLayout() && !containsFloats())
2697 return;
2698
2699 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2700 setChildNeedsLayout(markParents);
2701
2702 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002703 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002704
akling@apple.com525dae62014-01-03 20:22:09 +00002705 if (childrenInline())
2706 return;
2707
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002708 // Iterate over our children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002709 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2710 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2711 continue;
2712 if (!block.isRenderBlockFlow()) {
2713 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2714 block.setChildNeedsLayout(markParents);
2715 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002716 }
akling@apple.com525dae62014-01-03 20:22:09 +00002717 auto& blockFlow = toRenderBlockFlow(block);
2718 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2719 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002720 }
2721}
2722
2723void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2724{
2725 if (!m_floatingObjects)
2726 return;
2727
2728 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2729 auto end = floatingObjectSet.end();
2730
2731 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
2732 if (!next->isRenderBlockFlow() || next->isFloatingOrOutOfFlowPositioned() || toRenderBlock(next)->avoidsFloats())
2733 continue;
2734
2735 RenderBlockFlow* nextBlock = toRenderBlockFlow(next);
2736 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002737 RenderBox& floatingBox = (*it)->renderer();
2738 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002739 continue;
2740 if (nextBlock->containsFloat(floatingBox))
weinig@apple.com12840dc2013-10-22 23:59:08 +00002741 nextBlock->markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002742 }
2743 }
2744}
2745
weinig@apple.com31324fd2013-10-28 19:22:51 +00002746LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2747{
akling@apple.com827be9c2013-10-29 02:58:43 +00002748 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002749 return point;
2750
2751 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2752 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2753 // case.
2754 if (isHorizontalWritingMode())
2755 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2756 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2757}
2758
weinig@apple.com12840dc2013-10-22 23:59:08 +00002759LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002760{
2761 // There is no need to compute clearance if we have no floats.
2762 if (!containsFloats())
2763 return 0;
2764
2765 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002766 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002767 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002768 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002769 case CNONE:
2770 break;
2771 case CLEFT:
2772 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2773 break;
2774 case CRIGHT:
2775 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2776 break;
2777 case CBOTH:
2778 logicalBottom = lowestFloatLogicalBottom();
2779 break;
2780 }
2781
2782 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
andersca@apple.com86298632013-11-10 19:32:33 +00002783 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002784 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002785 LayoutUnit newLogicalTop = logicalTop;
2786 while (true) {
2787 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2788 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2789 return newLogicalTop - logicalTop;
2790
2791 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002792 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002793 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2794
2795 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002796 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2797 LayoutUnit childOldMarginLeft = child.marginLeft();
2798 LayoutUnit childOldMarginRight = child.marginRight();
2799 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002800
weinig@apple.com12840dc2013-10-22 23:59:08 +00002801 child.setLogicalTop(newLogicalTop);
2802 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002803 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002804 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002805 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2806
weinig@apple.com12840dc2013-10-22 23:59:08 +00002807 child.setLogicalTop(childOldLogicalTop);
2808 child.setLogicalWidth(childOldLogicalWidth);
2809 child.setMarginLeft(childOldMarginLeft);
2810 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002811
2812 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2813 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2814 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2815 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2816 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002817 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002818 return newLogicalTop - logicalTop;
2819 }
2820
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002821 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002822 ASSERT(newLogicalTop >= logicalTop);
2823 if (newLogicalTop < logicalTop)
2824 break;
2825 }
2826 ASSERT_NOT_REACHED();
2827 }
2828 return result;
2829}
2830
2831bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2832{
2833 if (!m_floatingObjects)
2834 return false;
2835
2836 LayoutPoint adjustedLocation = accumulatedOffset;
2837 if (isRenderView())
2838 adjustedLocation += toLayoutSize(toRenderView(*this).frameView().scrollPosition());
2839
2840 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2841 auto begin = floatingObjectSet.begin();
2842 for (auto it = floatingObjectSet.end(); it != begin;) {
2843 --it;
2844 FloatingObject* floatingObject = it->get();
2845 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2846 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2847 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2848 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2849 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2850 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2851 return true;
2852 }
2853 }
2854 }
2855
2856 return false;
2857}
2858
weinig@apple.com611b9292013-10-20 22:57:54 +00002859bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2860{
2861 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002862
darin@apple.come1be6ca2014-04-28 04:19:10 +00002863 if (auto simpleLineLayout = this->simpleLineLayout())
2864 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002865
weinig@apple.com611b9292013-10-20 22:57:54 +00002866 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2867}
2868
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002869void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2870{
akling@apple.com827be9c2013-10-29 02:58:43 +00002871 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002872 return;
2873
2874 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2875 // for either overflow or translations via relative positioning.
2876 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002877 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2878
weinig@apple.com611b9292013-10-20 22:57:54 +00002879 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
2880 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002881 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002882 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002883 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002884 }
2885 } else {
2886 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2887 if (!obj->isFloatingOrOutOfFlowPositioned()) {
2888 if (obj->isRenderBlockFlow() && !obj->hasOverflowClip())
2889 toRenderBlockFlow(obj)->adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002890 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002891 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002892 left = std::min(left, x + obj->x());
2893 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002894 }
2895 }
2896 }
2897 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002898
2899 if (m_floatingObjects) {
2900 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2901 auto end = floatingObjectSet.end();
2902 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2903 FloatingObject* r = it->get();
2904 // Only examine the object if our m_shouldPaint flag is set.
2905 if (r->shouldPaint()) {
2906 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2907 LayoutUnit floatRight = floatLeft + r->renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002908 left = std::min(left, floatLeft);
2909 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002910 }
2911 }
2912 }
2913}
2914
2915void RenderBlockFlow::fitBorderToLinesIfNeeded()
2916{
akling@apple.com827be9c2013-10-29 02:58:43 +00002917 if (style().borderFit() == BorderFitBorder || hasOverrideWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002918 return;
2919
2920 // Walk any normal flow lines to snugly fit.
2921 LayoutUnit left = LayoutUnit::max();
2922 LayoutUnit right = LayoutUnit::min();
2923 LayoutUnit oldWidth = contentWidth();
2924 adjustForBorderFit(0, left, right);
2925
2926 // Clamp to our existing edges. We can never grow. We only shrink.
2927 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2928 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002929 left = std::min(rightEdge, std::max(leftEdge, left));
2930 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002931
2932 LayoutUnit newContentWidth = right - left;
2933 if (newContentWidth == oldWidth)
2934 return;
2935
2936 setOverrideLogicalContentWidth(newContentWidth);
2937 layoutBlock(false);
2938 clearOverrideLogicalContentWidth();
2939}
2940
2941void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2942{
2943 if (logicalTop >= logicalBottom)
2944 return;
2945
antti@apple.combe9d3e12014-05-11 09:42:47 +00002946 // Floats currently affect the choice whether to use simple line layout path.
2947 if (m_simpleLineLayout) {
2948 invalidateLineLayoutPath();
2949 return;
2950 }
2951
weinig@apple.com611b9292013-10-20 22:57:54 +00002952 RootInlineBox* lowestDirtyLine = lastRootBox();
2953 RootInlineBox* afterLowest = lowestDirtyLine;
2954 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2955 afterLowest = lowestDirtyLine;
2956 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2957 }
2958
2959 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2960 afterLowest->markDirty();
2961 afterLowest = afterLowest->prevRootBox();
2962 }
2963}
2964
antti@apple.com0e632aa2013-10-22 21:03:38 +00002965int RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00002966{
2967 if (isWritingModeRoot() && !isRubyRun())
2968 return -1;
2969
2970 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00002971 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00002972
antti@apple.com940f5872013-10-24 20:31:11 +00002973 if (!hasLines())
2974 return -1;
weinig@apple.com611b9292013-10-20 22:57:54 +00002975
darin@apple.come1be6ca2014-04-28 04:19:10 +00002976 if (auto simpleLineLayout = this->simpleLineLayout())
2977 return SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00002978
akling@apple.comee3c8df2013-11-06 08:09:44 +00002979 ASSERT(firstRootBox());
2980 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00002981}
2982
2983int RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
2984{
2985 if (isWritingModeRoot() && !isRubyRun())
2986 return -1;
2987
2988 if (!childrenInline())
2989 return RenderBlock::inlineBlockBaseline(lineDirection);
2990
antti@apple.com0e632aa2013-10-22 21:03:38 +00002991 if (!hasLines()) {
2992 if (!hasLineIfEmpty())
2993 return -1;
akling@apple.com827be9c2013-10-29 02:58:43 +00002994 const FontMetrics& fontMetrics = firstLineStyle().fontMetrics();
weinig@apple.com611b9292013-10-20 22:57:54 +00002995 return fontMetrics.ascent()
2996 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
2997 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
2998 }
2999
darin@apple.come1be6ca2014-04-28 04:19:10 +00003000 if (auto simpleLineLayout = this->simpleLineLayout())
3001 return SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003002
akling@apple.comee3c8df2013-11-06 08:09:44 +00003003 bool isFirstLine = lastRootBox() == firstRootBox();
akling@apple.com827be9c2013-10-29 02:58:43 +00003004 const RenderStyle& style = isFirstLine ? firstLineStyle() : this->style();
akling@apple.comee3c8df2013-11-06 08:09:44 +00003005 return lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003006}
3007
weinig@apple.com12840dc2013-10-22 23:59:08 +00003008GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003009 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3010{
antti@apple.comfea51992013-10-28 13:39:23 +00003011 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003012
weinig@apple.com611b9292013-10-20 22:57:54 +00003013 GapRects result;
3014
3015 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3016
antti@apple.com0e632aa2013-10-22 21:03:38 +00003017 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003018 if (containsStart) {
3019 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
3020 // case.
3021 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3022 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3023 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3024 }
3025 return result;
3026 }
3027
3028 RootInlineBox* lastSelectedLine = 0;
3029 RootInlineBox* curr;
3030 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3031
3032 // Now paint the gaps for the lines.
3033 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3034 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3035 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3036
3037 if (!containsStart && !lastSelectedLine &&
3038 selectionState() != SelectionStart && selectionState() != SelectionBoth)
3039 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3040
3041 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3042 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003043 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003044 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3045 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3046 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3047
3048 lastSelectedLine = curr;
3049 }
3050
3051 if (containsStart && !lastSelectedLine)
3052 // VisibleSelection must start just after our last line.
3053 lastSelectedLine = lastRootBox();
3054
3055 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3056 // Go ahead and update our lastY to be the bottom of the last selected line.
3057 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3058 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3059 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3060 }
3061 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003062}
3063
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003064void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3065{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003066 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003067 return;
3068
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003069 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3070 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003071 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003072 flowFragment->initializeStyle();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003073 setRenderNamedFlowFragment(flowFragment);
3074 addChild(renderNamedFlowFragment());
3075 }
3076}
3077
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003078bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3079{
3080 // A block without floats or that expands to enclose them won't need a relayout
3081 // after a region range change. There is no overflow content needing relayout
3082 // in the region chain because the region range can only shrink after the estimation.
3083 if (!containsFloats() || expandsToEncloseOverhangingFloats())
3084 return false;
3085
3086 return true;
3087}
3088
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003089bool RenderBlockFlow::canHaveChildren() const
3090{
3091 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3092}
3093
3094bool RenderBlockFlow::canHaveGeneratedChildren() const
3095{
3096 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3097}
3098
3099bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3100{
3101 if (!isRenderNamedFlowFragmentContainer())
3102 return false;
3103
3104 return hasRelativeLogicalHeight() && !isRenderView();
3105}
3106
3107void RenderBlockFlow::updateLogicalHeight()
3108{
3109 RenderBlock::updateLogicalHeight();
3110
abucur@adobe.comfad53712014-05-06 17:30:40 +00003111 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003112 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003113 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3114 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003115}
3116
3117void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3118{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003119 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003120 if (rareData.m_renderNamedFlowFragment)
3121 rareData.m_renderNamedFlowFragment->destroy();
3122 rareData.m_renderNamedFlowFragment = flowFragment;
3123}
3124
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003125void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3126{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003127 if (flowThread || hasRareBlockFlowData()) {
3128 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3129 rareData.m_multiColumnFlowThread = flowThread;
3130 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003131}
3132
akling@apple.com525dae62014-01-03 20:22:09 +00003133static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003134{
akling@apple.com38f0a652014-02-06 21:24:17 +00003135 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003136}
3137
3138RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3139{
3140 ASSERT(i >= 0);
3141
akling@apple.com827be9c2013-10-29 02:58:43 +00003142 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003143 return nullptr;
3144
3145 if (childrenInline()) {
3146 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3147 if (!i--)
3148 return box;
3149 }
akling@apple.com525dae62014-01-03 20:22:09 +00003150 return nullptr;
3151 }
3152
3153 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3154 if (!shouldCheckLines(blockFlow))
3155 continue;
3156 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3157 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003158 }
3159
3160 return nullptr;
3161}
3162
3163int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3164{
akling@apple.com827be9c2013-10-29 02:58:43 +00003165 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003166 return 0;
3167
3168 int count = 0;
3169
3170 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003171 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003172 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003173 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003174 }
weinig@apple.com17140912013-10-19 19:55:40 +00003175 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3176 count++;
3177 if (box == stopRootInlineBox) {
3178 if (found)
3179 *found = true;
3180 break;
3181 }
3182 }
akling@apple.com525dae62014-01-03 20:22:09 +00003183 return count;
3184 }
3185
3186 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3187 if (!shouldCheckLines(blockFlow))
3188 continue;
3189 bool recursiveFound = false;
3190 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3191 if (recursiveFound) {
3192 if (found)
3193 *found = true;
3194 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003195 }
3196 }
3197
3198 return count;
3199}
3200
3201static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3202{
akling@apple.com827be9c2013-10-29 02:58:43 +00003203 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003204 return -1;
3205
3206 if (block.childrenInline()) {
3207 for (auto box = block.firstRootBox(); box; box = box->nextRootBox()) {
3208 if (++count == lineCount)
3209 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3210 }
3211 } else {
3212 RenderBox* normalFlowChildWithoutLines = 0;
3213 for (auto obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
akling@apple.com525dae62014-01-03 20:22:09 +00003214 if (obj->isRenderBlockFlow() && shouldCheckLines(toRenderBlockFlow(*obj))) {
weinig@apple.com17140912013-10-19 19:55:40 +00003215 int result = getHeightForLineCount(toRenderBlockFlow(*obj), lineCount, false, count);
3216 if (result != -1)
3217 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003218 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003219 normalFlowChildWithoutLines = obj;
3220 }
3221 if (normalFlowChildWithoutLines && !lineCount)
3222 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3223 }
3224
3225 return -1;
3226}
3227
3228int RenderBlockFlow::heightForLineCount(int lineCount)
3229{
3230 int count = 0;
3231 return getHeightForLineCount(*this, lineCount, true, count);
3232}
3233
3234void RenderBlockFlow::clearTruncation()
3235{
akling@apple.com827be9c2013-10-29 02:58:43 +00003236 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003237 return;
3238
3239 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003240 ensureLineBoxes();
3241
weinig@apple.com17140912013-10-19 19:55:40 +00003242 setHasMarkupTruncation(false);
3243 for (auto box = firstRootBox(); box; box = box->nextRootBox())
3244 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003245 return;
3246 }
3247
3248 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3249 if (shouldCheckLines(blockFlow))
3250 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003251 }
3252}
3253
weinig@apple.com3f23b382013-10-19 20:26:58 +00003254bool RenderBlockFlow::containsNonZeroBidiLevel() const
3255{
3256 for (auto root = firstRootBox(); root; root = root->nextRootBox()) {
3257 for (auto box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
3258 if (box->bidiLevel())
3259 return true;
3260 }
3261 }
3262 return false;
3263}
3264
weinig@apple.com611b9292013-10-20 22:57:54 +00003265Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3266{
3267 if (!box)
3268 return Position();
3269
3270 if (!box->renderer().nonPseudoNode())
3271 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3272
3273 if (!box->isInlineTextBox())
3274 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3275
3276 InlineTextBox* textBox = toInlineTextBox(box);
3277 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
3278}
3279
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003280VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003281{
3282 ASSERT(childrenInline());
3283
antti@apple.com940f5872013-10-24 20:31:11 +00003284 ensureLineBoxes();
3285
weinig@apple.com611b9292013-10-20 22:57:54 +00003286 if (!firstRootBox())
3287 return createVisiblePosition(0, DOWNSTREAM);
3288
akling@apple.com827be9c2013-10-29 02:58:43 +00003289 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3290 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003291
3292 // look for the closest line box in the root box which is at the passed-in y coordinate
3293 InlineBox* closestBox = 0;
3294 RootInlineBox* firstRootBoxWithChildren = 0;
3295 RootInlineBox* lastRootBoxWithChildren = 0;
3296 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003297 if (region && root->containingRegion() != region)
3298 continue;
3299
weinig@apple.com611b9292013-10-20 22:57:54 +00003300 if (!root->firstLeafChild())
3301 continue;
3302 if (!firstRootBoxWithChildren)
3303 firstRootBoxWithChildren = root;
3304
3305 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3306 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3307 break;
3308
3309 lastRootBoxWithChildren = root;
3310
3311 // check if this root line box is located at this y coordinate
3312 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3313 if (linesAreFlipped) {
3314 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3315 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3316 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3317
3318 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3319 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3320 continue;
3321 }
3322 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3323 if (closestBox)
3324 break;
3325 }
3326 }
3327
3328 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3329
3330 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3331 // y coordinate is below last root line box, pretend we hit it
3332 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3333 }
3334
3335 if (closestBox) {
3336 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003337 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003338 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3339 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3340 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3341 if (box->isLineBreak()) {
3342 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3343 box = newBox;
3344 }
3345 // y coordinate is above first root line box, so return the start of the first
3346 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3347 }
3348 }
3349
3350 // pass the box a top position that is inside it
3351 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3352 if (!isHorizontalWritingMode())
3353 point = point.transposedPoint();
3354 if (closestBox->renderer().isReplaced())
weinig@apple.com12840dc2013-10-22 23:59:08 +00003355 return positionForPointRespectingEditingBoundaries(*this, toRenderBox(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003356 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003357 }
3358
3359 if (lastRootBoxWithChildren) {
3360 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3361 ASSERT(moveCaretToBoundary);
3362 InlineBox* logicallyLastBox;
3363 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3364 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3365 }
3366
3367 // Can't reach this. We have a root line box, but it has no kids.
3368 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3369 // seems to hit this code path.
3370 return createVisiblePosition(0, DOWNSTREAM);
3371}
3372
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003373VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003374{
3375 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003376 return fragment->positionForPoint(point, region);
3377 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003378}
3379
3380
weinig@apple.com611b9292013-10-20 22:57:54 +00003381void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3382{
antti@apple.com940f5872013-10-24 20:31:11 +00003383 ASSERT(childrenInline());
3384
3385 ensureLineBoxes();
3386
weinig@apple.com611b9292013-10-20 22:57:54 +00003387 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003388 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3389 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003390 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3391 if (!rect.isEmpty())
zalan@apple.com376339c2014-08-28 04:24:31 +00003392 rects.append(snappedIntRect(rect));
weinig@apple.com611b9292013-10-20 22:57:54 +00003393 }
3394}
3395
3396void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3397{
3398 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003399
darin@apple.come1be6ca2014-04-28 04:19:10 +00003400 if (auto simpleLineLayout = this->simpleLineLayout()) {
3401 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003402 return;
3403 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003404 m_lineBoxes.paint(this, paintInfo, paintOffset);
3405}
3406
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003407bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003408{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003409 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003410 return false;
3411
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003412 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003413 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3414
3415 bool needsRelayout;
3416 bool neededRelayout = false;
3417 bool firstPass = true;
3418 do {
3419 // Column heights may change here because of balancing. We may have to do multiple layout
3420 // passes, depending on how the contents is fitted to the changed column heights. In most
3421 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3422 // passes than that, though, but the number of retries should not exceed the number of
3423 // columns, unless we have a bug.
3424 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003425 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3426 if (multicolSet->recalculateColumnHeight(firstPass))
3427 needsRelayout = true;
3428 if (needsRelayout) {
3429 // Once a column set gets a new column height, that column set and all successive column
3430 // sets need to be laid out over again, since their logical top will be affected by
3431 // this, and therefore their column heights may change as well, at least if the multicol
3432 // height is constrained.
3433 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003434 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003435 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003436 if (needsRelayout) {
3437 // Layout again. Column balancing resulted in a new height.
3438 neededRelayout = true;
3439 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3440 setChildNeedsLayout(MarkOnlyThis);
3441 if (firstPass)
3442 statePusher.pop();
3443 layoutBlock(false);
3444 }
3445 firstPass = false;
3446 } while (needsRelayout);
3447
3448 multiColumnFlowThread()->setInBalancingPass(false);
3449
3450 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003451}
3452
antti@apple.com940f5872013-10-24 20:31:11 +00003453bool RenderBlockFlow::hasLines() const
3454{
3455 ASSERT(childrenInline());
3456
darin@apple.come1be6ca2014-04-28 04:19:10 +00003457 if (auto simpleLineLayout = this->simpleLineLayout())
3458 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003459
3460 return lineBoxes().firstLineBox();
3461}
3462
antti@apple.com9e891c82014-05-22 06:12:34 +00003463void RenderBlockFlow::invalidateLineLayoutPath()
3464{
3465 switch (m_lineLayoutPath) {
3466 case UndeterminedPath:
3467 case ForceLineBoxesPath:
3468 ASSERT(!m_simpleLineLayout);
3469 return;
3470 case LineBoxesPath:
3471 ASSERT(!m_simpleLineLayout);
3472 m_lineLayoutPath = UndeterminedPath;
3473 return;
3474 case SimpleLinesPath:
3475 // The simple line layout may have become invalid.
3476 m_simpleLineLayout = nullptr;
3477 setNeedsLayout();
3478 m_lineLayoutPath = UndeterminedPath;
3479 return;
3480 }
3481 ASSERT_NOT_REACHED();
3482}
3483
antti@apple.com940f5872013-10-24 20:31:11 +00003484void RenderBlockFlow::layoutSimpleLines(LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
3485{
3486 ASSERT(!m_lineBoxes.firstLineBox());
3487
antti@apple.comfea51992013-10-28 13:39:23 +00003488 m_simpleLineLayout = SimpleLineLayout::create(*this);
antti@apple.com940f5872013-10-24 20:31:11 +00003489
antti@apple.comfea51992013-10-28 13:39:23 +00003490 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003491 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
3492
3493 repaintLogicalTop = lineLayoutTop;
3494 repaintLogicalBottom = lineLayoutTop + lineLayoutHeight;
3495
3496 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3497}
3498
3499void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3500{
antti@apple.com42fb53d2013-10-25 02:33:11 +00003501 ASSERT(m_lineLayoutPath == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003502 lineBoxes().deleteLineBoxes();
antti@apple.com940f5872013-10-24 20:31:11 +00003503 toRenderText(firstChild())->deleteLineBoxesBeforeSimpleLineLayout();
3504}
3505
3506void RenderBlockFlow::ensureLineBoxes()
3507{
antti@apple.com42fb53d2013-10-25 02:33:11 +00003508 m_lineLayoutPath = ForceLineBoxesPath;
antti@apple.comfea51992013-10-28 13:39:23 +00003509 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003510 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003511 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003512
3513#if !ASSERT_DISABLED
3514 LayoutUnit oldHeight = logicalHeight();
3515#endif
3516 bool didNeedLayout = needsLayout();
3517
3518 bool relayoutChildren = false;
3519 LayoutUnit repaintLogicalTop;
3520 LayoutUnit repaintLogicalBottom;
3521 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3522
3523 updateLogicalHeight();
3524 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3525
3526 if (!didNeedLayout)
3527 clearNeedsLayout();
3528}
3529
weinig@apple.com611b9292013-10-20 22:57:54 +00003530#ifndef NDEBUG
zalan@apple.comfac337f2014-08-29 17:55:34 +00003531void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003532{
weinig@apple.com611b9292013-10-20 22:57:54 +00003533 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003534 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003535
3536 if (auto simpleLineLayout = this->simpleLineLayout())
3537 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003538}
3539#endif
3540
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003541RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3542{
3543 if (hasRareBlockFlowData())
3544 return *m_rareBlockFlowData;
3545 materializeRareBlockFlowData();
3546 return *m_rareBlockFlowData;
3547}
3548
3549void RenderBlockFlow::materializeRareBlockFlowData()
3550{
3551 ASSERT(!hasRareBlockFlowData());
3552 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3553}
3554
aestes@apple.com6751d842014-01-12 02:51:25 +00003555#if ENABLE(IOS_TEXT_AUTOSIZING)
3556inline static bool isVisibleRenderText(RenderObject* renderer)
3557{
3558 if (!renderer->isText())
3559 return false;
3560 RenderText* renderText = toRenderText(renderer);
3561 return !renderText->linesBoundingBox().isEmpty() && !renderText->text()->containsOnlyWhitespace();
3562}
3563
3564inline static bool resizeTextPermitted(RenderObject* render)
3565{
3566 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3567 auto renderer = render->parent();
3568 while (renderer) {
3569 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003570 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003571 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003572 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003573 }
3574 renderer = renderer->parent();
3575 }
3576 return true;
3577}
3578
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003579int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003580{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003581 if (style().visibility() != VISIBLE)
3582 return 0;
3583 if (childrenInline())
3584 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003585 // Only descend into list items.
3586 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003587 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3588 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003589 return count;
3590}
3591
3592static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3593{
3594 if (!render->isRenderBlock())
3595 return true;
3596 if (render->isListItem())
3597 return render->style().height().type() != Fixed;
3598 return false;
3599}
3600
3601// For now, we auto size single lines of text the same as multiple lines.
3602// We've been experimenting with low values for single lines of text.
3603static inline float oneLineTextMultiplier(float specifiedSize)
3604{
3605 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3606}
3607
3608static inline float textMultiplier(float specifiedSize)
3609{
3610 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3611}
3612
3613void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3614{
3615 // Don't do any work if the block is smaller than the visible area.
3616 if (visibleWidth >= width())
3617 return;
3618
3619 unsigned lineCount;
3620 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003621 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003622 if (!count)
3623 lineCount = NO_LINE;
3624 else if (count == 1)
3625 lineCount = ONE_LINE;
3626 else
3627 lineCount = MULTI_LINE;
3628 } else
3629 lineCount = m_lineCountForTextAutosizing;
3630
3631 ASSERT(lineCount != NOT_SET);
3632 if (lineCount == NO_LINE)
3633 return;
3634
3635 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3636 float scale = visibleWidth / actualWidth;
3637 float minFontSize = roundf(size / scale);
3638
3639 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3640 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
3641 RenderText* text = toRenderText(descendent);
3642 RenderStyle& oldStyle = text->style();
3643 FontDescription fontDescription = oldStyle.fontDescription();
3644 float specifiedSize = fontDescription.specifiedSize();
3645 float scaledSize = roundf(specifiedSize * scale);
3646 if (scaledSize > 0 && scaledSize < minFontSize) {
3647 // Record the width of the block and the line count the first time we resize text and use it from then on for text resizing.
3648 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3649 if (m_lineCountForTextAutosizing == NOT_SET)
3650 m_lineCountForTextAutosizing = lineCount;
3651 if (m_widthForTextAutosizing == -1)
3652 m_widthForTextAutosizing = actualWidth;
3653
3654 float candidateNewSize = 0;
3655 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3656 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
3657 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text->textNode() && oldStyle.textSizeAdjust().isAuto())
3658 document().addAutoSizingNode(text->textNode(), candidateNewSize);
3659 }
3660 }
3661 }
3662}
3663#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3664
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003665RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3666{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003667 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3668 if (!flowThread)
3669 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003670
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003671 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003672
3673 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003674 flowThread->setChildNeedsLayout(MarkOnlyThis);
3675
3676 if (flowThread->needsLayout()) {
3677 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3678 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3679
3680 flowThread->invalidateRegions();
3681 flowThread->setNeedsHeightsRecalculation(true);
3682 flowThread->layout();
3683 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003684 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3685 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3686 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3687 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3688 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3689 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3690 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3691 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003692 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003693 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003694 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003695
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003696 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003697}
3698
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003699void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3700{
3701 if (multiColumnFlowThread())
3702 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003703 if (beforeChild) {
3704 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3705 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3706 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003707 RenderBlock::addChild(newChild, beforeChild);
3708}
3709
stavila@adobe.com2dae4b62014-05-27 16:36:09 +00003710RenderObject* RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003711{
3712 if (!documentBeingDestroyed()) {
3713 RenderFlowThread* flowThread = multiColumnFlowThread();
3714 if (flowThread && flowThread != &oldChild)
3715 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3716 }
stavila@adobe.com2dae4b62014-05-27 16:36:09 +00003717 return RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003718}
3719
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003720void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003721{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003722 // If we don't use columns or flow threads, then bail.
3723 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003724 return;
3725
3726 // We don't actually update any of the variables. We just subclassed to adjust our column height.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003727 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3728 LogicalExtentComputedValues computedValues;
3729 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3730 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003731 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003732 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003733 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3734 relayoutChildren = true;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003735 } else if (isRenderFlowThread()) {
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003736 RenderFlowThread* flowThread = toRenderFlowThread(this);
3737
3738 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3739 // is known. The page logical height thing in LayoutState is meaningless for flow
3740 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3741 // thread), but as long as it is used universally as a means to determine whether page
3742 // height is known or not, we need this. Page height is unknown when column balancing is
3743 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3744 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3745 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3746 // hack once the old multicol implementation is gone.
3747 pageLogicalHeight = flowThread->isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
3748
3749 pageLogicalHeightChanged = flowThread->pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003750 }
3751}
3752
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003753bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3754{
3755 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3756 // in the RenderView instead.
3757 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isRoot() || isBody());
3758
3759 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3760}
3761
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003762void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3763{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003764 bool destroyColumns = !requiresColumns(count);
3765 if (destroyColumns) {
3766 if (multiColumnFlowThread())
3767 destroyMultiColumnFlowThread();
3768 } else {
3769 if (!multiColumnFlowThread())
3770 createMultiColumnFlowThread();
3771 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003772 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3773 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003774 }
3775}
3776
hyatt@apple.com86919862014-01-27 16:27:45 +00003777void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle* style)
3778{
hyatt@apple.com86919862014-01-27 16:27:45 +00003779 if (!multiColumnFlowThread())
3780 return;
3781
3782 bool needsLayout = false;
3783 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
3784 bool newProgressionIsInline = style->hasInlineColumnAxis();
3785 if (oldProgressionIsInline != newProgressionIsInline) {
3786 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3787 needsLayout = true;
3788 }
3789
3790 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
3791 bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression;
3792 if (oldProgressionIsReversed != newProgressionIsReversed) {
3793 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3794 needsLayout = true;
3795 }
3796
3797 if (needsLayout)
3798 setNeedsLayoutAndPrefWidthsRecalc();
3799}
3800
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003801LayoutUnit RenderBlockFlow::computedColumnWidth() const
3802{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003803 if (multiColumnFlowThread())
3804 return multiColumnFlowThread()->computedColumnWidth();
3805 return contentLogicalWidth();
3806}
3807
3808unsigned RenderBlockFlow::computedColumnCount() const
3809{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003810 if (multiColumnFlowThread())
3811 return multiColumnFlowThread()->computedColumnCount();
3812
3813 return 1;
3814}
3815
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003816bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3817{
3818 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3819 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3820 return hasTopOverflow;
3821
3822 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3823 hasTopOverflow = !hasTopOverflow;
3824
3825 return hasTopOverflow;
3826}
3827
3828bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3829{
3830 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3831 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3832 return hasLeftOverflow;
3833
3834 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3835 hasLeftOverflow = !hasLeftOverflow;
3836
3837 return hasLeftOverflow;
3838}
3839
zalan@apple.comac6956c2014-09-05 14:18:06 +00003840struct InlineMinMaxIterator {
3841/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3842 inline min/max width calculations. Note the following about the way it walks:
3843 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3844 (2) We do not drill into the children of floats or replaced elements, since you can't break
3845 in the middle of such an element.
3846 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3847 distinct borders/margin/padding that contribute to the min/max width.
3848*/
3849 const RenderBlockFlow& parent;
3850 RenderObject* current;
3851 bool endOfInline;
3852 bool initial;
3853
3854 InlineMinMaxIterator(const RenderBlockFlow& p)
3855 : parent(p)
3856 , current(nullptr)
3857 , endOfInline(false)
3858 , initial(true)
3859 { }
3860
3861 RenderObject* next();
3862};
3863
3864RenderObject* InlineMinMaxIterator::next()
3865{
3866 RenderObject* result = nullptr;
3867 bool oldEndOfInline = endOfInline;
3868 endOfInline = false;
3869 do {
3870 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3871 result = current->firstChildSlow();
3872 else if (initial) {
3873 result = parent.firstChild();
3874 initial = false;
3875 }
3876
3877 if (!result) {
3878 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3879 if (!oldEndOfInline && current && current->isRenderInline()) {
3880 result = current;
3881 endOfInline = true;
3882 break;
3883 }
3884
3885 while (current && current != &parent) {
3886 result = current->nextSibling();
3887 if (result)
3888 break;
3889 current = current->parent();
3890 if (current && current != &parent && current->isRenderInline()) {
3891 result = current;
3892 endOfInline = true;
3893 break;
3894 }
3895 }
3896 }
3897
3898 if (!result)
3899 break;
3900
3901 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3902 break;
3903
3904 current = result;
3905 result = nullptr;
3906 } while (current || current == &parent);
3907 // Update our position.
3908 current = result;
3909 return result;
3910}
3911
3912static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3913{
3914 if (cssUnit.type() != Auto)
3915 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
3916 return 0;
3917}
3918
3919static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
3920{
3921 const RenderStyle& childStyle = child.style();
3922 if (endOfInline) {
3923 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
3924 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
3925 child.borderEnd();
3926 }
3927 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
3928 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
3929 child.borderStart();
3930}
3931
3932static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
3933{
3934 if (trailingSpaceChild && trailingSpaceChild->isText()) {
3935 // Collapse away the trailing space at the end of a block.
3936 RenderText* t = toRenderText(trailingSpaceChild);
3937 const UChar space = ' ';
3938 const Font& font = t->style().font(); // FIXME: This ignores first-line.
3939 float spaceWidth = font.width(RenderBlock::constructTextRun(t, font, &space, 1, t->style()));
3940 inlineMax -= spaceWidth + font.wordSpacing();
3941 if (inlineMin > inlineMax)
3942 inlineMin = inlineMax;
3943 }
3944}
3945
3946static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
3947{
3948 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
3949}
3950
3951void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3952{
3953 float inlineMax = 0;
3954 float inlineMin = 0;
3955
3956 const RenderStyle& styleToUse = style();
3957 RenderBlock* containingBlock = this->containingBlock();
3958 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
3959
3960 // If we are at the start of a line, we want to ignore all white-space.
3961 // Also strip spaces if we previously had text that ended in a trailing space.
3962 bool stripFrontSpaces = true;
3963 RenderObject* trailingSpaceChild = 0;
3964
3965 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
3966 // very specific cirucumstances (in order to match common WinIE renderings).
3967 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
3968 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
3969
3970 bool autoWrap, oldAutoWrap;
3971 autoWrap = oldAutoWrap = styleToUse.autoWrap();
3972
3973 InlineMinMaxIterator childIterator(*this);
3974
3975 // Only gets added to the max preffered width once.
3976 bool addedTextIndent = false;
3977 // Signals the text indent was more negative than the min preferred width
3978 bool hasRemainingNegativeTextIndent = false;
3979
3980 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
3981 RenderObject* prevFloat = 0;
3982 bool isPrevChildInlineFlow = false;
3983 bool shouldBreakLineAfterText = false;
3984 while (RenderObject* child = childIterator.next()) {
3985 autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
3986 child->style().autoWrap();
3987
3988 if (!child->isBR()) {
3989 // Step One: determine whether or not we need to go ahead and
3990 // terminate our current line. Each discrete chunk can become
3991 // the new min-width, if it is the widest chunk seen so far, and
3992 // it can also become the max-width.
3993
3994 // Children fall into three categories:
3995 // (1) An inline flow object. These objects always have a min/max of 0,
3996 // and are included in the iteration solely so that their margins can
3997 // be added in.
3998 //
3999 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4000 // These objects can always be on a line by themselves, so in this situation
4001 // we need to go ahead and break the current line, and then add in our own
4002 // margins and min/max width on its own line, and then terminate the line.
4003 //
4004 // (3) A text object. Text runs can have breakable characters at the start,
4005 // the middle or the end. They may also lose whitespace off the front if
4006 // we're already ignoring whitespace. In order to compute accurate min-width
4007 // information, we need three pieces of information.
4008 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4009 // starts with whitespace.
4010 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4011 // ends with whitespace.
4012 // (c) the min/max width of the string (trimmed for whitespace).
4013 //
4014 // If the text string starts with whitespace, then we need to go ahead and
4015 // terminate our current line (unless we're already in a whitespace stripping
4016 // mode.
4017 //
4018 // If the text string has a breakable character in the middle, but didn't start
4019 // with whitespace, then we add the width of the first non-breakable run and
4020 // then end the current line. We then need to use the intermediate min/max width
4021 // values (if any of them are larger than our current min/max). We then look at
4022 // the width of the last non-breakable run and use that to start a new line
4023 // (unless we end in whitespace).
4024 const RenderStyle& childStyle = child->style();
4025 float childMin = 0;
4026 float childMax = 0;
4027
4028 if (!child->isText()) {
4029 if (child->isLineBreakOpportunity()) {
4030 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4031 inlineMin = 0;
4032 continue;
4033 }
4034 // Case (1) and (2). Inline replaced and inline flow elements.
4035 if (child->isRenderInline()) {
4036 // Add in padding/border/margin from the appropriate side of
4037 // the element.
4038 float bpm = getBorderPaddingMargin(*toRenderInline(child), childIterator.endOfInline);
4039 childMin += bpm;
4040 childMax += bpm;
4041
4042 inlineMin += childMin;
4043 inlineMax += childMax;
4044
4045 child->setPreferredLogicalWidthsDirty(false);
4046 } else {
4047 // Inline replaced elts add in their margins to their min/max values.
4048 LayoutUnit margins = 0;
4049 Length startMargin = childStyle.marginStart();
4050 Length endMargin = childStyle.marginEnd();
4051 if (startMargin.isFixed())
4052 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4053 if (endMargin.isFixed())
4054 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4055 childMin += margins.ceilToFloat();
4056 childMax += margins.ceilToFloat();
4057 }
4058 }
4059
4060 if (!child->isRenderInline() && !child->isText()) {
4061 // Case (2). Inline replaced elements and floats.
4062 // Go ahead and terminate the current line as far as
4063 // minwidth is concerned.
4064 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4065 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4066
4067 bool clearPreviousFloat;
4068 if (child->isFloating()) {
4069 clearPreviousFloat = (prevFloat
4070 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4071 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4072 prevFloat = child;
4073 } else
4074 clearPreviousFloat = false;
4075
4076 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4077 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
4078 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4079 inlineMin = 0;
4080 }
4081
4082 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4083 if (clearPreviousFloat) {
4084 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4085 inlineMax = 0;
4086 }
4087
4088 // Add in text-indent. This is added in only once.
4089 if (!addedTextIndent && !child->isFloating()) {
4090 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4091 childMin += ceiledIndent;
4092 childMax += ceiledIndent;
4093
4094 if (childMin < 0)
4095 textIndent = LayoutUnit::fromFloatCeil(childMin);
4096 else
4097 addedTextIndent = true;
4098 }
4099
4100 // Add our width to the max.
4101 inlineMax += std::max<float>(0, childMax);
4102
4103 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
4104 if (child->isFloating())
4105 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4106 else
4107 inlineMin += childMin;
4108 } else {
4109 // Now check our line.
4110 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4111
4112 // Now start a new line.
4113 inlineMin = 0;
4114 }
4115
4116 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4117 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4118 inlineMin = 0;
4119 }
4120
4121 // We are no longer stripping whitespace at the start of a line.
4122 if (!child->isFloating()) {
4123 stripFrontSpaces = false;
4124 trailingSpaceChild = 0;
4125 }
4126 } else if (child->isText()) {
4127 // Case (3). Text.
4128 RenderText* t = toRenderText(child);
4129
4130 if (t->style().hasTextCombine() && t->isCombineText())
4131 toRenderCombineText(*t).combineText();
4132
4133 // Determine if we have a breakable character. Pass in
4134 // whether or not we should ignore any spaces at the front
4135 // of the string. If those are going to be stripped out,
4136 // then they shouldn't be considered in the breakable char
4137 // check.
4138 bool hasBreakableChar, hasBreak;
4139 float beginMin, endMin;
4140 bool beginWS, endWS;
4141 float beginMax, endMax;
4142 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
4143 hasBreakableChar, hasBreak, beginMax, endMax,
4144 childMin, childMax, stripFrontSpaces);
4145
4146 // This text object will not be rendered, but it may still provide a breaking opportunity.
4147 if (!hasBreak && !childMax) {
4148 if (autoWrap && (beginWS || endWS)) {
4149 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4150 inlineMin = 0;
4151 }
4152 continue;
4153 }
4154
4155 if (stripFrontSpaces)
4156 trailingSpaceChild = child;
4157 else
4158 trailingSpaceChild = 0;
4159
4160 // Add in text-indent. This is added in only once.
4161 float ti = 0;
4162 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4163 ti = textIndent.ceilToFloat();
4164 childMin += ti;
4165 beginMin += ti;
4166
4167 // It the text indent negative and larger than the child minimum, we re-use the remainder
4168 // in future minimum calculations, but using the negative value again on the maximum
4169 // will lead to under-counting the max pref width.
4170 if (!addedTextIndent) {
4171 childMax += ti;
4172 beginMax += ti;
4173 addedTextIndent = true;
4174 }
4175
4176 if (childMin < 0) {
4177 textIndent = childMin;
4178 hasRemainingNegativeTextIndent = true;
4179 }
4180 }
4181
4182 // If we have no breakable characters at all,
4183 // then this is the easy case. We add ourselves to the current
4184 // min and max and continue.
4185 if (!hasBreakableChar)
4186 inlineMin += childMin;
4187 else {
4188 // We have a breakable character. Now we need to know if
4189 // we start and end with whitespace.
4190 if (beginWS) {
4191 // Go ahead and end the current line.
4192 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4193 } else {
4194 inlineMin += beginMin;
4195 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4196 childMin -= ti;
4197 }
4198
4199 inlineMin = childMin;
4200
4201 if (endWS) {
4202 // We end in whitespace, which means we can go ahead
4203 // and end our current line.
4204 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4205 inlineMin = 0;
4206 shouldBreakLineAfterText = false;
4207 } else {
4208 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4209 inlineMin = endMin;
4210 shouldBreakLineAfterText = true;
4211 }
4212 }
4213
4214 if (hasBreak) {
4215 inlineMax += beginMax;
4216 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4217 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4218 inlineMax = endMax;
4219 addedTextIndent = true;
4220 } else
4221 inlineMax += std::max<float>(0, childMax);
4222 }
4223
4224 // Ignore spaces after a list marker.
4225 if (child->isListMarker())
4226 stripFrontSpaces = true;
4227 } else {
4228 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4229 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4230 inlineMin = inlineMax = 0;
4231 stripFrontSpaces = true;
4232 trailingSpaceChild = 0;
4233 addedTextIndent = true;
4234 }
4235
4236 if (!child->isText() && child->isRenderInline())
4237 isPrevChildInlineFlow = true;
4238 else
4239 isPrevChildInlineFlow = false;
4240
4241 oldAutoWrap = autoWrap;
4242 }
4243
4244 if (styleToUse.collapseWhiteSpace())
4245 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4246
4247 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4248 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4249}
4250
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004251}
4252// namespace WebCore