blob: ac91de69e8010333b31831a60a0d1f9c76aa937e [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());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000075 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000076
akling@apple.com827be9c2013-10-29 02:58:43 +000077 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000078
79 // If any height other than auto is specified in CSS, then we don't collapse our bottom
80 // margins with our children's margins. To do otherwise would be to risk odd visual
81 // effects when the children overflow out of the parent block and yet still collapse
82 // with it. We also don't collapse if we have any bottom border/padding.
83 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000084 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000085
weinig@apple.com12840dc2013-10-22 23:59:08 +000086 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000087
weinig@apple.com12840dc2013-10-22 23:59:08 +000088 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000089
weinig@apple.com12840dc2013-10-22 23:59:08 +000090 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
91 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000092}
93
akling@apple.com8f40c5b2013-10-27 22:54:07 +000094RenderBlockFlow::RenderBlockFlow(Element& element, PassRef<RenderStyle> style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +000095 : RenderBlock(element, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +000096#if ENABLE(IOS_TEXT_AUTOSIZING)
97 , m_widthForTextAutosizing(-1)
98 , m_lineCountForTextAutosizing(NOT_SET)
99#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000100{
weinig@apple.com611b9292013-10-20 22:57:54 +0000101 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000102}
103
akling@apple.com8f40c5b2013-10-27 22:54:07 +0000104RenderBlockFlow::RenderBlockFlow(Document& document, PassRef<RenderStyle> style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +0000105 : RenderBlock(document, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000106#if ENABLE(IOS_TEXT_AUTOSIZING)
107 , m_widthForTextAutosizing(-1)
108 , m_lineCountForTextAutosizing(NOT_SET)
109#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000110{
weinig@apple.com611b9292013-10-20 22:57:54 +0000111 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000112}
113
114RenderBlockFlow::~RenderBlockFlow()
115{
116}
117
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000118void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000119{
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000120 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
121 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000122 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 +0000123 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000124 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000125 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 +0000126 setMultiColumnFlowThread(flowThread);
127}
128
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000129void RenderBlockFlow::destroyMultiColumnFlowThread()
130{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000131 multiColumnFlowThread()->evacuateAndDestroy();
132 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000133}
134
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000135void RenderBlockFlow::insertedIntoTree()
136{
137 RenderBlock::insertedIntoTree();
138 createRenderNamedFlowFragmentIfNeeded();
139}
140
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000141void RenderBlockFlow::willBeDestroyed()
142{
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000143 if (renderNamedFlowFragment())
144 setRenderNamedFlowFragment(0);
weinig@apple.com611b9292013-10-20 22:57:54 +0000145
weinig@apple.com611b9292013-10-20 22:57:54 +0000146 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
147 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
148 destroyLeftoverChildren();
149
weinig@apple.com611b9292013-10-20 22:57:54 +0000150 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000151 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000152 // We can't wait for RenderBox::destroy to clear the selection,
153 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000154 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000155 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000156
157 // If we are an anonymous block, then our line boxes might have children
158 // that will outlast this block. In the non-anonymous block case those
159 // children will be destroyed by the time we return from this function.
160 if (isAnonymousBlock()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000161 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000162 while (auto childBox = box->firstChild())
163 childBox->removeFromParent();
164 }
165 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000166 } else if (parent())
167 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000168 }
169
akling@apple.com31dd4f42013-10-30 22:27:59 +0000170 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000171
dbates@webkit.org34f59002014-05-20 20:34:35 +0000172 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000173
174 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
175 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000176}
177
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000178void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000179{
180 if (m_floatingObjects)
181 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
182
183 HashSet<RenderBox*> oldIntrudingFloatSet;
184 if (!childrenInline() && m_floatingObjects) {
185 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000186 auto end = floatingObjectSet.end();
187 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
188 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000189 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000190 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000191 }
192 }
193
194 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
195 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000196 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000197 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000198 if (!oldIntrudingFloatSet.isEmpty())
199 markAllDescendantsWithFloatsForLayout();
200 return;
201 }
202
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000203 RendererToFloatInfoMap floatMap;
204
205 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000206 if (childrenInline())
207 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
208 else
209 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000210 }
211
212 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
213 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
214 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000215 if (!is<RenderBlockFlow>(parent()))
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000216 return;
217
218 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
219 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
220 // to avoid floats.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000221 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(*parent());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000222 bool parentHasFloats = false;
223 RenderObject* prev = previousSibling();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000224 while (prev && (!is<RenderBox>(*prev) || !is<RenderBlockFlow>(*prev) || downcast<RenderBlockFlow>(*prev).avoidsFloats() || downcast<RenderBlock>(prev)->createsNewFormattingContext())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000225 if (prev->isFloating())
226 parentHasFloats = true;
227 prev = prev->previousSibling();
228 }
229
robert@webkit.org97037ef2013-11-20 19:26:10 +0000230 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
231 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000232 LayoutUnit logicalTopOffset = logicalTop();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000233 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && prev && downcast<RenderBlockFlow>(*prev).isSelfCollapsingBlock()))
234 addIntrudingFloats(&parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000235
236 LayoutUnit logicalLeftOffset = 0;
237 if (prev)
cdumez@apple.com0abff8b2014-10-17 21:25:10 +0000238 logicalTopOffset -= downcast<RenderBox>(*prev).logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000239 else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000240 prev = &parentBlock;
241 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000242 }
243
244 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000245 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prev);
246 if (block.m_floatingObjects && block.lowestFloatLogicalBottom() > logicalTopOffset)
247 addIntrudingFloats(&block, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000248
249 if (childrenInline()) {
250 LayoutUnit changeLogicalTop = LayoutUnit::max();
251 LayoutUnit changeLogicalBottom = LayoutUnit::min();
252 if (m_floatingObjects) {
253 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000254 auto end = floatingObjectSet.end();
255 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000256 FloatingObject* floatingObject = it->get();
257 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject->renderer());
258 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000259 if (oldFloatingObject) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000260 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
261 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000262 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000263 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000264 } else {
265 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000266 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
267 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000268 }
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000269 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
270 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000271 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000272 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
273 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000274 }
275 }
276
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000277 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
278 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
279 oldFloatingObject->originatingLine()->markDirty();
280 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000281 } else {
282 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000283 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000284 }
285 }
286 }
287
darin@apple.com7cad7042013-09-24 05:53:55 +0000288 auto end = floatMap.end();
289 for (auto it = floatMap.begin(); it != end; ++it) {
290 FloatingObject* floatingObject = it->value.get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000291 if (!floatingObject->isDescendant()) {
292 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000293 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000294 }
295 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000296
297 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
298 } else if (!oldIntrudingFloatSet.isEmpty()) {
299 // If there are previously intruding floats that no longer intrude, then children with floats
300 // should also get layout because they might need their floating object lists cleared.
301 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
302 markAllDescendantsWithFloatsForLayout();
303 else {
304 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000305 auto end = floatingObjectSet.end();
306 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
307 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000308 if (!oldIntrudingFloatSet.isEmpty())
309 markAllDescendantsWithFloatsForLayout();
310 }
311 }
312}
313
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000314void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
315{
316 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
317 // The min/max intrinsic widths calculated really tell how much space elements need when
318 // laid out inside the columns. In order to eventually end up with the desired column width,
319 // we need to convert them to values pertaining to the multicol container.
320 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
321 LayoutUnit columnWidth;
322 LayoutUnit colGap = columnGap();
323 LayoutUnit gapExtra = (columnCount - 1) * colGap;
324 if (style().hasAutoColumnWidth())
325 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
326 else {
327 columnWidth = style().columnWidth();
328 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
329 }
330 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
331 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
332 // performing a layout pass, but this is not an appropriate time or place for layout. The
333 // good news is that if height is unconstrained and there are no explicit breaks, the
334 // resolved column-count really should be 1.
335 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
336 }
337}
338
339void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
340{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000341 if (childrenInline())
342 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
343 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000344 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
345
346 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
347
348 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
349
350 if (!style().autoWrap() && childrenInline()) {
351 // A horizontal marquee with inline children has no minimum width.
352 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
353 minLogicalWidth = 0;
354 }
355
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000356 if (is<RenderTableCell>(*this)) {
357 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000358 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
359 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
360 }
361
362 int scrollbarWidth = instrinsicScrollbarLogicalWidth();
363 maxLogicalWidth += scrollbarWidth;
364 minLogicalWidth += scrollbarWidth;
365}
366
367bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
368{
369 bool changed = recomputeLogicalWidth();
370
371 LayoutUnit oldColumnWidth = computedColumnWidth();
372 computeColumnCountAndWidth();
373
374 return changed || oldColumnWidth != computedColumnWidth();
375}
376
377LayoutUnit RenderBlockFlow::columnGap() const
378{
379 if (style().hasNormalColumnGap())
380 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
381 return style().columnGap();
382}
383
384void RenderBlockFlow::computeColumnCountAndWidth()
385{
386 // Calculate our column width and column count.
387 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
388 unsigned desiredColumnCount = 1;
389 LayoutUnit desiredColumnWidth = contentLogicalWidth();
390
391 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
392 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
393 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
394 return;
395 }
396
397 LayoutUnit availWidth = desiredColumnWidth;
398 LayoutUnit colGap = columnGap();
399 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
400 int colCount = std::max<int>(1, style().columnCount());
401
402 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
403 desiredColumnCount = colCount;
404 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
405 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
406 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
407 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
408 } else {
409 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
410 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
411 }
412 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
413}
414
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000415void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
416{
417 ASSERT(needsLayout());
418
419 if (!relayoutChildren && simplifiedLayout())
420 return;
421
422 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
423
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000424 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000425 relayoutChildren = true;
426
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000427 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000428
429 LayoutUnit previousHeight = logicalHeight();
430 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
431 // for consistency with other render classes?
432 setLogicalHeight(0);
433
434 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000435 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000436
akling@apple.com827be9c2013-10-29 02:58:43 +0000437 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000438 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000439
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000440 preparePaginationBeforeBlockLayout(relayoutChildren);
abucur@adobe.com0e81bc72013-10-22 14:50:37 +0000441 if (!relayoutChildren)
442 relayoutChildren = namedFlowFragmentNeedsUpdate();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000443
444 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
445 // our current maximal positive and negative margins. These values are used when we
446 // are collapsed with adjacent blocks, so for example, if you have block A and B
447 // collapsing together, then you'd take the maximal positive margin from both A and B
448 // and subtract it from the maximal negative margin from both A and B to get the
449 // true collapsed margin. This algorithm is recursive, so when we finish layout()
450 // our block knows its current maximal positive/negative values.
451 //
452 // Start out by setting our margin values to our current margins. Table cells have
453 // no margins, so we don't fill in the values for table cells.
454 bool isCell = isTableCell();
455 if (!isCell) {
456 initMaxMarginValues();
457
akling@apple.com827be9c2013-10-29 02:58:43 +0000458 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
459 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000460 setPaginationStrut(0);
461 }
462
463 LayoutUnit repaintLogicalTop = 0;
464 LayoutUnit repaintLogicalBottom = 0;
465 LayoutUnit maxFloatLogicalBottom = 0;
466 if (!firstChild() && !isAnonymousBlock())
467 setChildrenInline(true);
468 if (childrenInline())
469 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
470 else
471 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
472
473 // Expand our intrinsic height to encompass floats.
474 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000475 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000476 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
477
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000478 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000479 ASSERT(!shouldBreakAtLineToAvoidWidow());
480 return;
481 }
482
483 // Calculate our new height.
484 LayoutUnit oldHeight = logicalHeight();
485 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
486
487 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
488 // This ensures the size information is correctly computed for the last auto-height region receiving content.
cdumez@apple.com3abcc792014-10-20 03:42:03 +0000489 if (is<RenderFlowThread>(*this))
490 downcast<RenderFlowThread>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000491
492 updateLogicalHeight();
493 LayoutUnit newHeight = logicalHeight();
494 if (oldHeight != newHeight) {
495 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
496 // 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 +0000497 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
498 if (blockFlow.isFloatingOrOutOfFlowPositioned())
499 continue;
500 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
501 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000502 }
503 }
504 }
505
506 bool heightChanged = (previousHeight != newHeight);
507 if (heightChanged)
508 relayoutChildren = true;
509
510 layoutPositionedObjects(relayoutChildren || isRoot());
511
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000512 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
513 computeOverflow(oldClientAfterEdge);
514
515 statePusher.pop();
516
517 fitBorderToLinesIfNeeded();
518
519 if (view().layoutState()->m_pageLogicalHeight)
520 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
521
522 updateLayerTransform();
523
524 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
525 // we overflow or not.
526 updateScrollInfoAfterLayout();
527
528 // FIXME: This repaint logic should be moved into a separate helper function!
529 // Repaint with our new bounds if they are different from our old bounds.
530 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000531 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000532 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
533 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
534 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
535 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
536 if (hasOverflowClip()) {
537 // 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.
538 // 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.
539 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000540 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
541 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000542 }
543
544 LayoutRect repaintRect;
545 if (isHorizontalWritingMode())
546 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
547 else
548 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
549
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000550 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
551
552 if (hasOverflowClip()) {
553 // Adjust repaint rect for scroll offset
554 repaintRect.move(-scrolledContentOffset());
555
556 // Don't allow this rect to spill out of our overflow box.
557 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
558 }
559
560 // Make sure the rect is still non-empty after intersecting for overflow above
561 if (!repaintRect.isEmpty()) {
562 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
563 if (hasReflection())
564 repaintRectangle(reflectedRect(repaintRect));
565 }
566 }
567
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000568 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000569}
570
571void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
572{
573 dirtyForLayoutFromPercentageHeightDescendants();
574
575 LayoutUnit beforeEdge = borderAndPaddingBefore();
576 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
577
578 setLogicalHeight(beforeEdge);
579
580 // Lay out our hypothetical grid line as though it occurs at the top of the block.
581 if (view().layoutState()->lineGrid() == this)
582 layoutLineGridBox();
583
584 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000585 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000586
587 // Fieldsets need to find their legend and position it inside the border of the object.
588 // The legend then gets skipped during normal layout. The same is true for ruby text.
589 // It doesn't get included in the normal layout process but is instead skipped.
590 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
591
592 LayoutUnit previousFloatLogicalBottom = 0;
593 maxFloatLogicalBottom = 0;
594
595 RenderBox* next = firstChildBox();
596
597 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000598 RenderBox& child = *next;
599 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000600
weinig@apple.com12840dc2013-10-22 23:59:08 +0000601 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000602 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
603
604 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
605
weinig@apple.com12840dc2013-10-22 23:59:08 +0000606 if (child.isOutOfFlowPositioned()) {
607 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000608 adjustPositionedBlock(child, marginInfo);
609 continue;
610 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000611 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000612 insertFloatingObject(child);
613 adjustFloatingBlock(marginInfo);
614 continue;
615 }
616
617 // Lay out the child.
618 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
619 }
620
621 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
622 // determining the correct collapsed bottom margin information.
623 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
624}
625
antti@apple.com940f5872013-10-24 20:31:11 +0000626void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
627{
antti@apple.com42fb53d2013-10-25 02:33:11 +0000628 if (m_lineLayoutPath == UndeterminedPath)
629 m_lineLayoutPath = SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath;
630
631 if (m_lineLayoutPath == SimpleLinesPath) {
antti@apple.com940f5872013-10-24 20:31:11 +0000632 deleteLineBoxesBeforeSimpleLineLayout();
633 layoutSimpleLines(repaintLogicalTop, repaintLogicalBottom);
634 return;
635 }
636
antti@apple.comfea51992013-10-28 13:39:23 +0000637 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000638 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
639}
640
weinig@apple.com12840dc2013-10-22 23:59:08 +0000641void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000642{
643 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
644 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
645
646 // The child is a normal flow object. Compute the margins we will use for collapsing now.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000647 child.computeAndSetBlockDirectionMargins(this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000648
649 // Try to guess our correct logical top position. In most cases this guess will
650 // be correct. Only if we're wrong (when we compute the real logical top position)
651 // will we have to potentially relayout.
652 LayoutUnit estimateWithoutPagination;
653 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
654
655 // 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 +0000656 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000657 LayoutUnit oldLogicalTop = logicalTopForChild(child);
658
659#if !ASSERT_DISABLED
660 LayoutSize oldLayoutDelta = view().layoutDelta();
661#endif
662 // Go ahead and position the child as though it didn't collapse with the top.
663 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
664 estimateRegionRangeForBoxChild(child);
665
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000666 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000667 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000668 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000669 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000670 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
671 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
672 // very large elements. If it does the comparison with oldLogicalTop might yield a
673 // false negative as adding and removing margins, borders etc from a saturated number
674 // might yield incorrect results. If this is the case always mark for layout.
675 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000676 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000677 // If an element might be affected by the presence of floats, then always mark it for
678 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000679 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000680 if (fb > logicalTopEstimate)
681 markDescendantsWithFloats = true;
682 }
683
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000684 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000685 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000686 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000687 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000688 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000689 }
690
weinig@apple.com12840dc2013-10-22 23:59:08 +0000691 if (!child.needsLayout())
692 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000693
weinig@apple.com12840dc2013-10-22 23:59:08 +0000694 bool childHadLayout = child.everHadLayout();
695 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000696 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000697 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000698
699 // Cache if we are at the top of the block right now.
700 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
701
702 // Now determine the correct ypos based off examination of collapsing margin
703 // values.
704 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
705
706 // Now check for clear.
707 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
708
709 bool paginated = view().layoutState()->isPaginated();
710 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000711 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000712
713 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
714
715 // Now we have a final top position. See if it really does end up being different from our estimate.
716 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
717 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000718 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
719 if (child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000720 // The child's width depends on the line width.
721 // When the child shifts to clear an item, its width can
722 // change (because it has more available line width).
723 // So go ahead and mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000724 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000725 }
726
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000727 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000728 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000729 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000730 if (!child.needsLayout())
731 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000732 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000733 }
734
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000735 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000736 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000737
738 // In case our guess was wrong, relayout the child.
739 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000740
741 // We are no longer at the top of the block if we encounter a non-empty child.
742 // 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 +0000743 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000744 marginInfo.setAtBeforeSideOfBlock(false);
745
746 // Now place the child in the correct left position
747 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
748
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000749 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000750 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000751 if (mustSeparateMarginAfterForChild(child)) {
752 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
753 marginInfo.clearMargin();
754 }
755 // If the child has overhanging floats that intrude into following siblings (or possibly out
756 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000757 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000758 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000759
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000760 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000761 if (childOffset.width() || childOffset.height()) {
762 view().addLayoutDelta(childOffset);
763
764 // If the child moved, we have to repaint it as well as any floating/positioned
765 // descendants. An exception is if we need a layout. In this case, we know we're going to
766 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000767 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
768 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000769 }
770
weinig@apple.com12840dc2013-10-22 23:59:08 +0000771 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
772 child.repaint();
773 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000774 }
775
776 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000777 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
778 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000779 // Check for an after page/column break.
780 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
781 if (newHeight != height())
782 setLogicalHeight(newHeight);
783 }
784
785 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
786}
787
weinig@apple.com12840dc2013-10-22 23:59:08 +0000788void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000789{
790 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000791 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000792
793 LayoutUnit logicalTop = logicalHeight();
794 updateStaticInlinePositionForChild(child, logicalTop);
795
796 if (!marginInfo.canCollapseWithMarginBefore()) {
797 // Positioned blocks don't collapse margins, so add the margin provided by
798 // the container now. The child's own margin is added later when calculating its logical top.
799 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
800 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
801 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
802 }
803
weinig@apple.com12840dc2013-10-22 23:59:08 +0000804 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000805 if (childLayer->staticBlockPosition() != logicalTop) {
806 childLayer->setStaticBlockPosition(logicalTop);
807 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000808 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000809 }
810}
811
robert@webkit.org97037ef2013-11-20 19:26:10 +0000812LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
813{
814 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000815 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000816 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
817 return marginValuesForChild(*this).positiveMarginBefore();
818 return LayoutUnit();
819}
820
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000821void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
822{
823 LayoutUnit startPosition = borderStart() + paddingStart();
824 if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
825 startPosition -= verticalScrollbarWidth();
826 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
827
828 // Add in our start margin.
829 LayoutUnit childMarginStart = marginStartForChild(child);
830 LayoutUnit newPosition = startPosition + childMarginStart;
831
832 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
833 // to shift over as necessary to dodge any floats that might get in the way.
834 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
835 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
836
837 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
838}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000839
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000840void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
841{
842 // The float should be positioned taking into account the bottom margin
843 // of the previous flow. We add that margin into the height, get the
844 // float positioned properly, and then subtract the margin out of the
845 // height again. In the case of self-collapsing blocks, we always just
846 // use the top margins, since the self-collapsing block collapsed its
847 // own bottom margin into its top margin.
848 //
849 // Note also that the previous flow may collapse its margin into the top of
850 // our block. If this is the case, then we do not add the margin in to our
851 // height when computing the position of the float. This condition can be tested
852 // for by simply calling canCollapseWithMarginBefore. See
853 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
854 // an example of this scenario.
855 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
856 setLogicalHeight(logicalHeight() + marginOffset);
857 positionNewFloats();
858 setLogicalHeight(logicalHeight() - marginOffset);
859}
860
weinig@apple.com12840dc2013-10-22 23:59:08 +0000861void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop)
862{
akling@apple.com827be9c2013-10-29 02:58:43 +0000863 if (child.style().isOriginalDisplayInlineType())
weinig@apple.com12840dc2013-10-22 23:59:08 +0000864 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
865 else
866 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
867}
868
869void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
870{
871 if (flowThreadContainingBlock()) {
872 // Shift the inline position to exclude the region offset.
873 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
874 }
875 child.layer()->setStaticInlinePosition(inlinePosition);
876}
877
878RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000879{
880 LayoutUnit childBeforePositive = 0;
881 LayoutUnit childBeforeNegative = 0;
882 LayoutUnit childAfterPositive = 0;
883 LayoutUnit childAfterNegative = 0;
884
885 LayoutUnit beforeMargin = 0;
886 LayoutUnit afterMargin = 0;
887
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000888 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000889
890 // If the child has the same directionality as we do, then we can just return its
891 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000892 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000893 if (childRenderBlock) {
894 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
895 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
896 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
897 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
898 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000899 beforeMargin = child.marginBefore();
900 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000901 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000902 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000903 // The child has a different directionality. If the child is parallel, then it's just
904 // flipped relative to us. We can use the margins for the opposite edges.
905 if (childRenderBlock) {
906 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
907 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
908 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
909 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
910 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000911 beforeMargin = child.marginAfter();
912 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000913 }
914 } else {
915 // The child is perpendicular to us, which means its margins don't collapse but are on the
916 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
917 beforeMargin = marginBeforeForChild(child);
918 afterMargin = marginAfterForChild(child);
919 }
920
921 // Resolve uncollapsing margins into their positive/negative buckets.
922 if (beforeMargin) {
923 if (beforeMargin > 0)
924 childBeforePositive = beforeMargin;
925 else
926 childBeforeNegative = -beforeMargin;
927 }
928 if (afterMargin) {
929 if (afterMargin > 0)
930 childAfterPositive = afterMargin;
931 else
932 childAfterNegative = -afterMargin;
933 }
934
935 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
936}
937
weinig@apple.com12840dc2013-10-22 23:59:08 +0000938LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000939{
940 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
941 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +0000942 bool childIsSelfCollapsing = child.isSelfCollapsingBlock();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000943
944 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
945 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
946
947 // Get the four margin values for the child and cache them.
948 const MarginValues childMargins = marginValuesForChild(child);
949
950 // Get our max pos and neg top margins.
951 LayoutUnit posTop = childMargins.positiveMarginBefore();
952 LayoutUnit negTop = childMargins.negativeMarginBefore();
953
954 // For self-collapsing blocks, collapse our bottom margins into our
955 // top to get new posTop and negTop values.
956 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000957 posTop = std::max(posTop, childMargins.positiveMarginAfter());
958 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000959 }
960
961 // See if the top margin is quirky. We only care if this child has
962 // margins that will collapse with us.
963 bool topQuirk = hasMarginBeforeQuirk(child);
964
965 if (marginInfo.canCollapseWithMarginBefore()) {
966 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
967 // This child is collapsing with the top of the
968 // block. If it has larger margin values, then we need to update
969 // our own maximal values.
970 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +0000971 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000972
973 // The minute any of the margins involved isn't a quirk, don't
974 // collapse it away, even if the margin is smaller (www.webreference.com
975 // has an example of this, a <dt> with 0.8em author-specified inside
976 // a <dl> inside a <td>.
977 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
978 setHasMarginBeforeQuirk(false);
979 marginInfo.setDeterminedMarginBeforeQuirk(true);
980 }
981
982 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
983 // We have no top margin and our top child has a quirky margin.
984 // We will pick up this quirky margin and pass it through.
985 // This deals with the <td><div><p> case.
986 // Don't do this for a block that split two inlines though. You do
987 // still apply margins in this case.
988 setHasMarginBeforeQuirk(true);
989 } else
990 // The before margin of the container will also discard all the margins it is collapsing with.
991 setMustDiscardMarginBefore();
992 }
993
994 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
995 if (childDiscardMarginBefore) {
996 marginInfo.setDiscardMargin(true);
997 marginInfo.clearMargin();
998 }
999
1000 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1001 marginInfo.setHasMarginBeforeQuirk(topQuirk);
1002
1003 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1004 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001005
1006 LayoutUnit clearanceForSelfCollapsingBlock;
1007 RenderObject* prev = child.previousSibling();
1008 // 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
1009 // 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
1010 // 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.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001011 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prev) && downcast<RenderBlockFlow>(*prev).isSelfCollapsingBlock()) {
1012 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prev).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001013 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1014 }
1015
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001016 if (childIsSelfCollapsing) {
1017 // 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.
1018 // Also, the child's top position equals the logical height of the container.
1019 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1020 // This child has no height. We need to compute our
1021 // position before we collapse the child's margins together,
1022 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001023 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1024 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001025 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1026
1027 // Now collapse the child's margins together, which means examining our
1028 // bottom margin values as well.
1029 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1030 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1031
1032 if (!marginInfo.canCollapseWithMarginBefore())
1033 // We need to make sure that the position of the self-collapsing block
1034 // is correct, since it could have overflowing content
1035 // that needs to be positioned correctly (e.g., a block that
1036 // had a specified height of 0 but that actually had subcontent).
1037 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1038 }
1039 } else {
1040 if (mustSeparateMarginBeforeForChild(child)) {
1041 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1042 // If we are at the before side of the block and we collapse, ignore the computed margin
1043 // and just add the child margin to the container height. This will correctly position
1044 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001045 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001046 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
1047 logicalTop = logicalHeight();
1048 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1049 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1050 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1051 // We're collapsing with a previous sibling's margins and not
1052 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001053 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001054 logicalTop = logicalHeight();
1055 }
1056
1057 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1058
1059 if (!marginInfo.discardMargin()) {
1060 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1061 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1062 } else
1063 marginInfo.clearMargin();
1064
1065 if (marginInfo.margin())
1066 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
1067 }
1068
1069 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1070 // collapsed into the page edge.
1071 LayoutState* layoutState = view().layoutState();
1072 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1073 && hasNextPage(beforeCollapseLogicalTop)) {
1074 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001075 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001076 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1077 }
1078
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001079 if (is<RenderBlockFlow>(prev) && !prev->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001080 // 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
1081 // any floats from the parent will now overhang.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001082 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prev);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001083 LayoutUnit oldLogicalHeight = logicalHeight();
1084 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001085 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001086 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001087 setLogicalHeight(oldLogicalHeight);
1088
1089 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1090 // 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
1091 // floats in the parent that overhang |child|'s new logical top.
1092 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
1093 if (logicalTopIntrudesIntoFloat && containsFloats() && !child.avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1094 child.setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001095 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001096
1097 return logicalTop;
1098}
1099
weinig@apple.com12840dc2013-10-22 23:59:08 +00001100LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001101{
1102 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1103 if (!heightIncrease)
1104 return yPos;
1105
weinig@apple.com12840dc2013-10-22 23:59:08 +00001106 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001107 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1108
1109 // For self-collapsing blocks that clear, they can still collapse their
1110 // margins with following siblings. Reset the current margins to represent
1111 // the self-collapsing block's margins only.
1112 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001113 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001114 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001115 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1116 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001117 } else
1118 marginInfo.clearMargin();
1119 marginInfo.setDiscardMargin(childDiscardMargin);
1120
1121 // CSS2.1 states:
1122 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1123 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1124 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1125 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1126 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001127 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001128 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1129 wouldCollapseMarginsWithParent = false;
1130 }
1131 if (wouldCollapseMarginsWithParent)
1132 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1133
robert@webkit.org97037ef2013-11-20 19:26:10 +00001134 // 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
1135 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1136 // 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
1137 // margins can collapse at the correct vertical position.
1138 // 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
1139 // (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],
1140 // i.e., clearance = [height of float] - margin-top".
1141 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001142 } else
1143 // Increase our height by the amount we had to clear.
1144 setLogicalHeight(logicalHeight() + heightIncrease);
1145
1146 if (marginInfo.canCollapseWithMarginBefore()) {
1147 // We can no longer collapse with the top of the block since a clear
1148 // occurred. The empty blocks collapse into the cleared block.
1149 // FIXME: This isn't quite correct. Need clarification for what to do
1150 // if the height the cleared block is offset by is smaller than the
1151 // margins involved.
1152 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1153 marginInfo.setAtBeforeSideOfBlock(false);
1154
1155 // 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 +00001156 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001157 }
1158
robert@webkit.org97037ef2013-11-20 19:26:10 +00001159 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001160}
1161
weinig@apple.com12840dc2013-10-22 23:59:08 +00001162void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001163{
1164 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1165 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1166 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001167 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001168 return;
1169
1170 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1171 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001172 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001173 positiveMarginBefore = 0;
1174 negativeMarginBefore = 0;
1175 discardMarginBefore = true;
1176 return;
1177 }
1178
1179 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001180 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1181 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001182
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001183 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001184 return;
1185
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001186 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001187 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001188 return;
1189
weinig@apple.com12840dc2013-10-22 23:59:08 +00001190 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001191 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1192 return;
1193
weinig@apple.com12840dc2013-10-22 23:59:08 +00001194 RenderBox* grandchildBox = childBlock.firstChildBox();
1195 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001196 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1197 break;
1198 }
1199
1200 // 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 +00001201 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001202 return;
1203
1204 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1205 if (grandchildBox->needsLayout()) {
1206 grandchildBox->computeAndSetBlockDirectionMargins(this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001207 if (is<RenderBlock>(*grandchildBox)) {
1208 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1209 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1210 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001211 }
1212 }
1213
1214 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001215 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001216}
1217
weinig@apple.com12840dc2013-10-22 23:59:08 +00001218LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001219{
1220 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1221 // relayout if there are intruding floats.
1222 LayoutUnit logicalTopEstimate = logicalHeight();
1223 if (!marginInfo.canCollapseWithMarginBefore()) {
1224 LayoutUnit positiveMarginBefore = 0;
1225 LayoutUnit negativeMarginBefore = 0;
1226 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001227 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001228 // Try to do a basic estimation of how the collapse is going to go.
1229 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1230 } else {
1231 // Use the cached collapsed margin values from a previous layout. Most of the time they
1232 // will be right.
1233 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001234 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1235 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001236 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1237 }
1238
1239 // Collapse the result with our current margins.
1240 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001241 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001242 }
1243
1244 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1245 // page.
1246 LayoutState* layoutState = view().layoutState();
1247 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1248 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001249 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001250
1251 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1252
1253 estimateWithoutPagination = logicalTopEstimate;
1254
1255 if (layoutState->isPaginated()) {
1256 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1257 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1258
1259 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1260 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1261
cdumez@apple.come9437792014-10-08 23:33:43 +00001262 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1263 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001264 }
1265
1266 return logicalTopEstimate;
1267}
1268
1269void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1270{
1271 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1272 // 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.
1273 // Don't update the max margin values because we won't need them anyway.
1274 if (marginInfo.discardMargin()) {
1275 setMustDiscardMarginAfter();
1276 return;
1277 }
1278
1279 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1280 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001281 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001282
1283 if (!marginInfo.hasMarginAfterQuirk())
1284 setHasMarginAfterQuirk(false);
1285
1286 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1287 // We have no bottom margin and our last child has a quirky margin.
1288 // We will pick up this quirky margin and pass it through.
1289 // This deals with the <td><div><p> case.
1290 setHasMarginAfterQuirk(true);
1291 }
1292}
1293
1294void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1295{
1296 marginInfo.setAtAfterSideOfBlock(true);
1297
robert@webkit.org97037ef2013-11-20 19:26:10 +00001298 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1299 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1300 // to perform now is at the child's margin-top - so adjust our height to that position.
1301 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001302 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1303 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001304
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001305 // If we can't collapse with children then go ahead and add in the bottom margin.
1306 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1307 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1308 setLogicalHeight(logicalHeight() + marginInfo.margin());
1309
1310 // Now add in our bottom border/padding.
1311 setLogicalHeight(logicalHeight() + afterSide);
1312
1313 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1314 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001315 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001316
1317 // Update our bottom collapsed margin info.
1318 setCollapsedBottomMargin(marginInfo);
1319}
1320
1321void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1322{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001323 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001324 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001325 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001326 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001327 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001328
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001329 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1330 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001331}
1332
1333void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1334{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001335 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001336 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001337 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001338 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001339 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001340
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001341 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1342 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001343}
1344
1345void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1346{
akling@apple.com827be9c2013-10-29 02:58:43 +00001347 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001348 ASSERT(value);
1349 return;
1350 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001351
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001352 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001353 if (!value)
1354 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001355 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001356 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001357
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001358 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001359}
1360
1361void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1362{
akling@apple.com827be9c2013-10-29 02:58:43 +00001363 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001364 ASSERT(value);
1365 return;
1366 }
1367
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001368 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001369 if (!value)
1370 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001371 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001372 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001373
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001374 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001375}
1376
1377bool RenderBlockFlow::mustDiscardMarginBefore() const
1378{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001379 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001380}
1381
1382bool RenderBlockFlow::mustDiscardMarginAfter() const
1383{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001384 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001385}
1386
weinig@apple.com12840dc2013-10-22 23:59:08 +00001387bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001388{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001389 ASSERT(!child.selfNeedsLayout());
1390 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001391 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001392 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001393 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001394
1395 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1396 // In case the boxes are perpendicular we assume the property is not specified.
1397 return false;
1398}
1399
weinig@apple.com12840dc2013-10-22 23:59:08 +00001400bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001401{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001402 ASSERT(!child.selfNeedsLayout());
1403 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001404 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001405 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001406 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001407
1408 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1409 return false;
1410}
1411
weinig@apple.com12840dc2013-10-22 23:59:08 +00001412bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001413{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001414 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001415 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001416 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001417 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001418 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001419 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001420
1421 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1422 return false;
1423}
1424
weinig@apple.com12840dc2013-10-22 23:59:08 +00001425bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001426{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001427 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001428 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001429 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001430 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001431 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001432 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001433
1434 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1435 return false;
1436}
1437
weinig@apple.com12840dc2013-10-22 23:59:08 +00001438static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001439{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001440 RenderBlock* curr = child.containingBlock();
1441 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001442 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001443 return true;
1444 if (curr->isFloatingOrOutOfFlowPositioned())
1445 return false;
1446 curr = curr->containingBlock();
1447 }
1448 return true;
1449}
1450
weinig@apple.com12840dc2013-10-22 23:59:08 +00001451LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001452{
1453 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001454 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001455 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001456 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001457 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 +00001458 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001459 bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
1460 || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001461 || (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001462 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001463 if (checkColumnBreaks) {
1464 if (isInsideMulticolFlowThread)
1465 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001466 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001467 if (checkRegionBreaks) {
1468 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001469 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001470 return logicalOffset + offsetBreakAdjustment;
1471 }
1472 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1473 }
1474 return logicalOffset;
1475}
1476
weinig@apple.com12840dc2013-10-22 23:59:08 +00001477LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001478{
1479 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001480 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001481 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001482 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001483 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 +00001484 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001485 bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
1486 || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001487 || (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001488 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1489 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1490
1491 // So our margin doesn't participate in the next collapsing steps.
1492 marginInfo.clearMargin();
1493
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001494 if (checkColumnBreaks) {
1495 if (isInsideMulticolFlowThread)
1496 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001497 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001498 if (checkRegionBreaks) {
1499 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001500 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001501 return logicalOffset + marginOffset + offsetBreakAdjustment;
1502 }
1503 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1504 }
1505 return logicalOffset;
1506}
1507
weinig@apple.com12840dc2013-10-22 23:59:08 +00001508LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001509{
cdumez@apple.come9437792014-10-08 23:33:43 +00001510 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001511
1512 if (estimateWithoutPagination != logicalTopAfterClear) {
1513 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1514 // position.
1515 setLogicalHeight(logicalTopAfterClear);
1516 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1517
weinig@apple.com12840dc2013-10-22 23:59:08 +00001518 if (child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001519 // The child's width depends on the line width.
1520 // When the child shifts to clear an item, its width can
1521 // change (because it has more available line width).
1522 // So go ahead and mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001523 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001524 }
1525
1526 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001527 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001528 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001529 if (!child.needsLayout())
1530 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001531 }
1532
1533 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001534 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001535 }
1536
1537 LayoutUnit oldTop = logicalTopAfterClear;
1538
1539 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1540 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1541
1542 if (pageLogicalHeightForOffset(result)) {
1543 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001544 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001545 if (spaceShortage > 0) {
1546 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1547 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1548 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1549 // This should be improved, though, because here we just pretend that the child is
1550 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1551 // where there's no child content, border or padding. In other words, we risk stretching more
1552 // than necessary.
1553 setPageBreak(result, spaceShortage);
1554 }
1555 }
1556
1557 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1558 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1559 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1560
1561 LayoutUnit paginationStrut = 0;
1562 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1563 if (unsplittableAdjustmentDelta)
1564 paginationStrut = unsplittableAdjustmentDelta;
1565 else if (childRenderBlock && childRenderBlock->paginationStrut())
1566 paginationStrut = childRenderBlock->paginationStrut();
1567
1568 if (paginationStrut) {
1569 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1570 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1571 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1572 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1573 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1574 // and pushes to the next page anyway, so not too concerned about it.
1575 setPaginationStrut(result + paginationStrut);
1576 if (childRenderBlock)
1577 childRenderBlock->setPaginationStrut(0);
1578 } else
1579 result += paginationStrut;
1580 }
1581
1582 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
1583 setLogicalHeight(logicalHeight() + (result - oldTop));
1584
1585 // Return the final adjusted logical top.
1586 return result;
1587}
1588
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001589static inline LayoutUnit calculateMinimumPageHeight(RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001590{
1591 // We may require a certain minimum number of lines per page in order to satisfy
1592 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001593 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001594 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001595 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001596 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1597 line = line->prevRootBox();
1598
1599 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1600 // adjustLinePositionForPagination() for more details.
1601 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001602 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001603 }
1604 return lineBottom - lineTop;
1605}
1606
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001607void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001608{
1609 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1610 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1611 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1612 // of the first column.
1613 //
1614 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1615 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1616 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1617 // for overflow to occur), and then cache visible overflow for each column rect.
1618 //
1619 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1620 // content that paints in a previous column (and content that paints in the following column).
1621 //
1622 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1623 // at least make positive leading work in typical cases.
1624 //
1625 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1626 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1627 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001628 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001629 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001630 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1631 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001632 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001633 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001634 logicalOffset += delta;
1635 lineBox->setPaginationStrut(0);
1636 lineBox->setIsFirstAfterPageBreak(false);
1637 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1638 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1639 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1640 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001641 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001642 // 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.
1643 // 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 +00001644 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001645 }
1646
1647 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1648 // We are so tall that we are bigger than a page. Before we give up and just leave the line where it is, try drilling into the
1649 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1650 // able to fit with the blank space and overflow excluded, we will give the line its own page with the highest non-blank element being aligned with the
1651 // top of the page.
1652 // FIXME: We are still honoring gigantic margins, which does leave open the possibility of blank pages caused by this heuristic. It remains to be seen whether or not
1653 // this will be a real-world issue. For now we don't try to deal with this problem.
1654 logicalOffset = intMaxForLayoutUnit;
1655 logicalBottom = intMinForLayoutUnit;
1656 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1657 lineHeight = logicalBottom - logicalOffset;
1658 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1659 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1660 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1661 }
1662
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001663 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001664 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001665
1666 int lineIndex = lineCount(lineBox);
1667 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001668 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001669 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001670 setDidBreakAtLineToAvoidWidow();
1671 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001672 // If we have a non-uniform page height, then we have to shift further possibly.
1673 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1674 return;
1675 if (lineHeight > pageLogicalHeight) {
1676 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001677 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001678 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001679 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1680 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001681 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001682 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1683 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001684 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001685 && !isOutOfFlowPositioned() && !isTableCell()) {
1686 auto firstRootBox = this->firstRootBox();
1687 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1688 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
1689 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1690 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001691 delta += remainingLogicalHeight;
1692 lineBox->setPaginationStrut(remainingLogicalHeight);
1693 lineBox->setIsFirstAfterPageBreak(true);
1694 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001695 } else if (remainingLogicalHeight == pageLogicalHeight) {
1696 // We're at the very top of a page or column.
1697 if (lineBox != firstRootBox())
1698 lineBox->setIsFirstAfterPageBreak(true);
1699 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1700 setPageBreak(logicalOffset, lineHeight);
1701 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001702}
1703
1704void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1705{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001706 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001707 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1708 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001709}
1710
abucur@adobe.comfc497132013-10-04 08:49:21 +00001711void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1712{
1713 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001714 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001715 return;
1716
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001717 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001718}
1719
1720void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1721{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001722 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001723 return;
1724
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001725 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001726}
1727
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001728void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1729{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001730 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001731 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001732 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001733
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001734 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001735}
1736
1737bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1738{
1739 if (!shouldBreakAtLineToAvoidWidow())
1740 return false;
1741
1742 statePusher.pop();
1743 setEverHadLayout(true);
1744 layoutBlock(false);
1745 return true;
1746}
1747
weinig@apple.com31324fd2013-10-28 19:22:51 +00001748bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1749{
1750 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1751
1752 RenderFlowThread* flowThread = flowThreadContainingBlock();
1753 if (!flowThread)
1754 return true; // Printing and multi-column both make new pages to accommodate content.
1755
1756 // See if we're in the last region.
1757 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001758 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001759 if (!region)
1760 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001761
weinig@apple.com31324fd2013-10-28 19:22:51 +00001762 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001763 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001764 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001765
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001766 RenderRegion* startRegion = nullptr;
1767 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001768 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001769 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001770}
1771
1772LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1773{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001774 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001775 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001776
1777 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001778 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1779 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1780 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1781 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1782 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1783 || !hasNextPage(logicalOffset))
1784 return logicalOffset;
1785 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1786 if (remainingLogicalHeight < childLogicalHeight) {
1787 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1788 return logicalOffset;
1789 return logicalOffset + remainingLogicalHeight;
1790 }
1791 return logicalOffset;
1792}
1793
1794bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1795{
1796 bool checkRegion = false;
1797 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1798 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1799 if (minimumLogicalHeight <= pageLogicalHeight)
1800 return true;
1801 if (!hasNextPage(logicalOffset + adjustment))
1802 return false;
1803 adjustment += pageLogicalHeight;
1804 checkRegion = true;
1805 }
1806 return !checkRegion;
1807}
1808
1809void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1810{
1811 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1812 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1813}
1814
1815void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1816{
1817 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1818 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001819}
1820
1821LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1822{
1823 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1824 if (!pageLogicalHeight)
1825 return logicalOffset;
1826
1827 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1828 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1829 if (pageBoundaryRule == ExcludePageBoundary)
1830 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1831 return logicalOffset + remainingLogicalHeight;
1832}
1833
1834LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1835{
1836 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1837 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1838
1839 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1840 RenderFlowThread* flowThread = flowThreadContainingBlock();
1841 if (!flowThread) {
1842 LayoutUnit pageLogicalHeight = view().layoutState()->pageLogicalHeight();
1843 if (!pageLogicalHeight)
1844 return 0;
1845 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
1846 }
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001847 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001848}
1849
1850LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1851{
1852 RenderFlowThread* flowThread = flowThreadContainingBlock();
1853 if (!flowThread)
1854 return view().layoutState()->m_pageLogicalHeight;
1855 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1856}
1857
1858LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1859{
1860 offset += offsetFromLogicalTopOfFirstPage();
1861
1862 RenderFlowThread* flowThread = flowThreadContainingBlock();
1863 if (!flowThread) {
1864 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1865 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1866 if (pageBoundaryRule == IncludePageBoundary) {
1867 // If includeBoundaryPoint is true the line exactly on the top edge of a
1868 // column will act as being part of the previous column.
1869 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1870 }
1871 return remainingHeight;
1872 }
1873
1874 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1875}
1876
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001877LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1878{
1879 // This method is required because regions do not fragment monolithic elements but instead
1880 // they let them overflow the region they flow in. This behaviour is different from the
1881 // multicol/printing implementations, which have not yet been updated to correctly handle
1882 // monolithic elements.
1883 // As a result, for the moment, this method will only be used for regions, the multicol and
1884 // printing implementations will stick to the existing behaviour until their fragmentation
1885 // implementation is updated to match the regions implementation.
1886 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1887 return logicalHeightForChild(child);
1888
1889 // For unsplittable elements, this method will just return the height of the element that
1890 // fits into the current region, without the height of the part that overflows the region.
1891 // This is done for all regions, except the last one because in that case, the logical
1892 // height of the flow thread needs to also
1893 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1894 return logicalHeightForChild(child);
1895
1896 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1897 // the entire unsplittable child because any following children will not be moved to the next page
1898 // so they will need to be laid out below the current unsplittable child.
1899 LayoutUnit childLogicalTop = logicalTopForChild(child);
1900 if (!hasNextPage(childLogicalTop))
1901 return logicalHeightForChild(child);
1902
1903 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1904 return std::min(child.logicalHeight(), remainingLogicalHeight);
1905}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001906
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001907void RenderBlockFlow::layoutLineGridBox()
1908{
akling@apple.com827be9c2013-10-29 02:58:43 +00001909 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001910 setLineGridBox(0);
1911 return;
1912 }
1913
1914 setLineGridBox(0);
1915
akling@apple.com1aa97b02013-10-31 21:59:49 +00001916 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001917 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1918 lineGridBox->setConstructed();
1919 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1920 VerticalPositionCache verticalPositionCache;
1921 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1922
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00001923 setLineGridBox(WTF::move(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001924
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001925 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1926 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1927 // to this grid.
1928}
1929
weinig@apple.com12840dc2013-10-22 23:59:08 +00001930bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001931{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001932 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001933}
1934
1935void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1936{
1937 RenderBlock::styleDidChange(diff, oldStyle);
1938
1939 // After our style changed, if we lose our ability to propagate floats into next sibling
1940 // blocks, then we need to find the top most parent containing that overhanging float and
1941 // then mark its descendants with floats for layout and clear all floats from its next
1942 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1943 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1944 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
1945 RenderBlockFlow* parentBlock = this;
1946 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001947
weinig@apple.comc77041e2013-12-14 18:05:45 +00001948 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
1949 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00001950 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00001951 if (ancestor.hasOverhangingFloats()) {
akling@apple.comf3028052013-11-04 08:46:06 +00001952 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
1953 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00001954 if (ancestor.hasOverhangingFloat(renderer)) {
1955 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00001956 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001957 }
1958 }
1959 }
1960 }
1961
1962 parentBlock->markAllDescendantsWithFloatsForLayout();
1963 parentBlock->markSiblingsWithFloatsForLayout();
1964 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00001965
akling@apple.com8f40c5b2013-10-27 22:54:07 +00001966 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00001967 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00001968
antti@apple.com9e891c82014-05-22 06:12:34 +00001969 if (diff >= StyleDifferenceRepaint) {
1970 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
1971 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
1972 invalidateLineLayoutPath();
1973 }
1974
hyatt@apple.comfdb12812014-06-23 18:56:52 +00001975 if (multiColumnFlowThread())
1976 updateStylesForColumnChildren();
1977}
1978
1979void RenderBlockFlow::updateStylesForColumnChildren()
1980{
1981 for (auto child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
1982 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001983}
1984
akling@apple.combdae43242013-10-25 12:00:20 +00001985void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001986{
akling@apple.com827be9c2013-10-29 02:58:43 +00001987 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001988 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
1989
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00001990 if (oldStyle) {
1991 EPosition oldPosition = oldStyle->position();
1992 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00001993
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00001994 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
1995 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
1996 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00001997 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001998 }
1999
2000 RenderBlock::styleWillChange(diff, newStyle);
2001}
2002
antti@apple.coma2c7f242013-10-22 22:37:25 +00002003void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002004{
2005 if (containsFloats())
2006 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002007
antti@apple.comfea51992013-10-28 13:39:23 +00002008 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002009 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002010 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002011 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002012 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002013
antti@apple.coma2c7f242013-10-22 22:37:25 +00002014 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002015}
2016
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002017void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002018{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002019 // When a portion of the render tree is being detached, anonymous blocks
2020 // will be combined as their children are deleted. In this process, the
2021 // anonymous block later in the tree is merged into the one preceeding it.
2022 // It can happen that the later block (this) contains floats that the
2023 // previous block (toBlockFlow) did not contain, and thus are not in the
2024 // floating objects list for toBlockFlow. This can result in toBlockFlow
2025 // containing floats that are not in it's floating objects list, but are in
2026 // the floating objects lists of siblings and parents. This can cause
2027 // problems when the float itself is deleted, since the deletion code
2028 // assumes that if a float is not in it's containing block's floating
2029 // objects list, it isn't in any floating objects list. In order to
2030 // preserve this condition (removing it has serious performance
2031 // implications), we need to copy the floating objects from the old block
2032 // (this) to the new block (toBlockFlow). The float's metrics will likely
2033 // all be wrong, but since toBlockFlow is already marked for layout, this
2034 // will get fixed before anything gets displayed.
2035 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2036 if (m_floatingObjects) {
2037 if (!toBlockFlow->m_floatingObjects)
2038 toBlockFlow->createFloatingObjects();
2039
2040 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2041 auto end = fromFloatingObjectSet.end();
2042
2043 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2044 FloatingObject* floatingObject = it->get();
2045
2046 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002047 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002048 continue;
2049
2050 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2051 }
2052 }
2053}
2054
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002055void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002056{
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002057 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2058 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2059 moveFloatsTo(&toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002060}
2061
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002062void RenderBlockFlow::addOverflowFromFloats()
2063{
2064 if (!m_floatingObjects)
2065 return;
2066
2067 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2068 auto end = floatingObjectSet.end();
2069 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2070 FloatingObject* r = it->get();
2071 if (r->isDescendant())
2072 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
2073 }
2074}
2075
2076void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2077{
2078 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2079
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002080 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002081 addOverflowFromFloats();
2082}
2083
2084void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2085{
2086 // Repaint any overhanging floats (if we know we're the one to paint them).
2087 // Otherwise, bail out.
2088 if (!hasOverhangingFloats())
2089 return;
2090
2091 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2092 // in this block. Better yet would be to push extra state for the containers of other floats.
2093 LayoutStateDisabler layoutStateDisabler(&view());
2094 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2095 auto end = floatingObjectSet.end();
2096 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2097 FloatingObject* floatingObject = it->get();
2098 // Only repaint the object if it is overhanging, is not in its own layer, and
2099 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2100 // condition is replaced with being a descendant of us.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002101 if (logicalBottomForFloat(floatingObject) > logicalHeight()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002102 && !floatingObject->renderer().hasSelfPaintingLayer()
2103 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
2104 floatingObject->renderer().repaint();
2105 floatingObject->renderer().repaintOverhangingFloats(false);
2106 }
2107 }
2108}
2109
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002110void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002111{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002112 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002113
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002114 if (!multiColumnFlowThread() || paintInfo.context->paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002115 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002116
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002117 // Iterate over our children and paint the column rules as needed.
2118 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2119 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2120 columnSet.paintColumnRules(paintInfo, childPoint);
2121 }
2122}
2123
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002124void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2125{
2126 if (!m_floatingObjects)
2127 return;
2128
2129 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2130 auto end = floatingObjectSet.end();
2131 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2132 FloatingObject* r = it->get();
2133 // Only paint the object if our m_shouldPaint flag is set.
2134 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
2135 PaintInfo currentPaintInfo(paintInfo);
2136 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2137 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
2138 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2139 r->renderer().paint(currentPaintInfo, childPoint);
2140 if (!preservePhase) {
2141 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2142 r->renderer().paint(currentPaintInfo, childPoint);
2143 currentPaintInfo.phase = PaintPhaseFloat;
2144 r->renderer().paint(currentPaintInfo, childPoint);
2145 currentPaintInfo.phase = PaintPhaseForeground;
2146 r->renderer().paint(currentPaintInfo, childPoint);
2147 currentPaintInfo.phase = PaintPhaseOutline;
2148 r->renderer().paint(currentPaintInfo, childPoint);
2149 }
2150 }
2151 }
2152}
2153
weinig@apple.com12840dc2013-10-22 23:59:08 +00002154void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002155{
2156 if (m_floatingObjects) {
2157 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2158 auto end = floatingObjectSet.end();
2159 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2160 FloatingObject* floatingObject = it->get();
2161 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2162 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
2163 floatingObject->renderer().width(), floatingObject->renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002164 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002165 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
zalan@apple.com376339c2014-08-28 04:24:31 +00002166 paintInfo->context->clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002167 }
2168 }
2169}
2170
2171void RenderBlockFlow::createFloatingObjects()
2172{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002173 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002174}
2175
2176void RenderBlockFlow::removeFloatingObjects()
2177{
2178 if (!m_floatingObjects)
2179 return;
2180
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002181 markSiblingsWithFloatsForLayout();
2182
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002183 m_floatingObjects->clear();
2184}
2185
weinig@apple.com12840dc2013-10-22 23:59:08 +00002186FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002187{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002188 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002189
2190 // Create the list of special objects if we don't aleady have one
2191 if (!m_floatingObjects)
2192 createFloatingObjects();
2193 else {
2194 // Don't insert the floatingObject again if it's already in the list
2195 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002196 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002197 if (it != floatingObjectSet.end())
2198 return it->get();
2199 }
2200
2201 // Create the special floatingObject entry & append it to the list
2202
weinig@apple.com12840dc2013-10-22 23:59:08 +00002203 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002204
2205 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
2206 // Just go ahead and lay out the float.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002207 bool isChildRenderBlock = floatBox.isRenderBlock();
2208 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2209 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002210
2211 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2212 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002213 floatBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002214 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002215 floatBox.updateLogicalWidth();
2216 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002217 }
2218
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002219 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002220
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00002221 return m_floatingObjects->add(WTF::move(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002222}
2223
weinig@apple.com12840dc2013-10-22 23:59:08 +00002224void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002225{
2226 if (m_floatingObjects) {
2227 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002228 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002229 if (it != floatingObjectSet.end()) {
2230 FloatingObject* floatingObject = it->get();
2231 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002232 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2233 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002234
2235 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2236 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2237 logicalBottom = LayoutUnit::max();
2238 else {
2239 // Special-case zero- and less-than-zero-height floats: those don't touch
2240 // the line that they're on, but it still needs to be dirtied. This is
2241 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002242 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002243 }
2244 if (floatingObject->originatingLine()) {
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002245 floatingObject->originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002246 if (!selfNeedsLayout()) {
2247 ASSERT(&floatingObject->originatingLine()->renderer() == this);
2248 floatingObject->originatingLine()->markDirty();
2249 }
2250#if !ASSERT_DISABLED
2251 floatingObject->setOriginatingLine(0);
2252#endif
2253 }
2254 markLinesDirtyInBlockRange(0, logicalBottom);
2255 }
2256 m_floatingObjects->remove(floatingObject);
2257 }
2258 }
2259}
2260
2261void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2262{
2263 if (!containsFloats())
2264 return;
2265
2266 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2267 FloatingObject* curr = floatingObjectSet.last().get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002268 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002269 m_floatingObjects->remove(curr);
2270 if (floatingObjectSet.isEmpty())
2271 break;
2272 curr = floatingObjectSet.last().get();
2273 }
2274}
2275
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002276LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2277{
2278 LayoutUnit offset = fixedOffset;
2279 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2280 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2281 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2282}
2283
2284LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2285{
2286 LayoutUnit offset = fixedOffset;
2287 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2288 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2289 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2290}
2291
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002292LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002293{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002294 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002295 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002296 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002297
andersca@apple.com86298632013-11-10 19:32:33 +00002298 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002299
2300 LayoutUnit floatLogicalLeft;
2301
2302 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002303 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2304
2305 if (isInitialLetter) {
2306 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2307 if (letterClearance > 0) {
2308 logicalTopOffset += letterClearance;
2309 setLogicalHeight(logicalHeight() + letterClearance);
2310 }
2311 }
2312
akling@apple.com827be9c2013-10-29 02:58:43 +00002313 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002314 LayoutUnit heightRemainingLeft = 1;
2315 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002316 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2317 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002318 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002319 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002320 if (insideFlowThread) {
2321 // Have to re-evaluate all of our offsets, since they may have changed.
2322 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2323 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002324 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002325 }
2326 }
andersca@apple.com86298632013-11-10 19:32:33 +00002327 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002328 } else {
2329 LayoutUnit heightRemainingLeft = 1;
2330 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002331 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2332 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002333 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002334 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002335 if (insideFlowThread) {
2336 // Have to re-evaluate all of our offsets, since they may have changed.
2337 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2338 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002339 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002340 }
2341 }
2342 // Use the original width of the float here, since the local variable
2343 // |floatLogicalWidth| was capped to the available line width. See
2344 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002345 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002346 }
2347
hyatt@apple.com87515262014-09-04 21:20:12 +00002348 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002349 const RenderStyle& style = firstLineStyle();
2350 const FontMetrics& fontMetrics = style.fontMetrics();
2351 if (fontMetrics.hasCapHeight()) {
2352 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2353 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2354
2355 // Make an adjustment to align with the cap height of a theoretical block line.
2356 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2357 logicalTopOffset += adjustment;
2358
2359 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2360 // positive for raised and negative for sunken).
2361 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2362
2363 // 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.
2364 if (dropHeightDelta < 0) {
2365 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2366 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2367 }
2368
2369 // 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
2370 // empty lines beside the first letter.
2371 if (dropHeightDelta > 0)
2372 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2373 }
2374 }
2375
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002376 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2377}
2378
2379bool RenderBlockFlow::positionNewFloats()
2380{
2381 if (!m_floatingObjects)
2382 return false;
2383
2384 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2385 if (floatingObjectSet.isEmpty())
2386 return false;
2387
2388 // If all floats have already been positioned, then we have no work to do.
2389 if (floatingObjectSet.last()->isPlaced())
2390 return false;
2391
2392 // Move backwards through our floating object list until we find a float that has
2393 // already been positioned. Then we'll be able to move forward, positioning all of
2394 // the new floats that need it.
2395 auto it = floatingObjectSet.end();
2396 --it; // Go to last item.
2397 auto begin = floatingObjectSet.begin();
2398 FloatingObject* lastPlacedFloatingObject = 0;
2399 while (it != begin) {
2400 --it;
2401 if ((*it)->isPlaced()) {
2402 lastPlacedFloatingObject = it->get();
2403 ++it;
2404 break;
2405 }
2406 }
2407
2408 LayoutUnit logicalTop = logicalHeight();
2409
2410 // The float cannot start above the top position of the last positioned float.
2411 if (lastPlacedFloatingObject)
andersca@apple.com86298632013-11-10 19:32:33 +00002412 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002413
2414 auto end = floatingObjectSet.end();
2415 // Now walk through the set of unpositioned floats and place them.
2416 for (; it != end; ++it) {
2417 FloatingObject* floatingObject = it->get();
2418 // The containing block is responsible for positioning floats, so if we have floats in our
2419 // list that come from somewhere else, do not attempt to position them.
2420 if (floatingObject->renderer().containingBlock() != this)
2421 continue;
2422
weinig@apple.com12840dc2013-10-22 23:59:08 +00002423 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002424
akling@apple.com827be9c2013-10-29 02:58:43 +00002425 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002426
weinig@apple.com12840dc2013-10-22 23:59:08 +00002427 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002428
akling@apple.com827be9c2013-10-29 02:58:43 +00002429 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002430 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002431 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002432 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002433
2434 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2435
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002436 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002437
2438 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2439 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2440
2441 estimateRegionRangeForBoxChild(childBox);
2442
2443 LayoutState* layoutState = view().layoutState();
2444 bool isPaginated = layoutState->isPaginated();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002445 if (isPaginated && !childBox.needsLayout())
2446 childBox.markForPaginationRelayoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002447
weinig@apple.com12840dc2013-10-22 23:59:08 +00002448 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002449
2450 if (isPaginated) {
2451 // If we are unsplittable and don't fit, then we need to move down.
2452 // We include our margins as part of the unsplittable area.
2453 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2454
2455 // See if we have a pagination strut that is making us move down further.
2456 // Note that an unsplittable child can't also have a pagination strut, so this is
2457 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002458 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002459 if (childBlock && childBlock->paginationStrut()) {
2460 newLogicalTop += childBlock->paginationStrut();
2461 childBlock->setPaginationStrut(0);
2462 }
2463
2464 if (newLogicalTop != floatLogicalLocation.y()) {
2465 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
2466
2467 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002468 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002469
2470 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2471 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2472
2473 if (childBlock)
2474 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002475 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002476 }
2477
2478 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002479 childBox.setNeedsLayout(MarkOnlyThis);
2480 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002481 }
2482 }
2483
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002484 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002485
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002486 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002487
2488 m_floatingObjects->addPlacedObject(floatingObject);
2489
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002490#if ENABLE(CSS_SHAPES)
2491 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002492 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002493#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002494 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002495 if (childBox.checkForRepaintDuringLayout())
2496 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002497 }
2498 return true;
2499}
2500
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002501void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002502{
2503 positionNewFloats();
2504 // set y position
2505 LayoutUnit newY = 0;
2506 switch (clear) {
2507 case CLEFT:
2508 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2509 break;
2510 case CRIGHT:
2511 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2512 break;
2513 case CBOTH:
2514 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002515 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002516 default:
2517 break;
2518 }
2519 if (height() < newY)
2520 setLogicalHeight(newY);
2521}
2522
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002523LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002524{
2525 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002526 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002527
2528 return fixedOffset;
2529}
2530
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002531LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002532{
2533 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002534 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002535
2536 return fixedOffset;
2537}
2538
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002539LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002540{
2541 if (!m_floatingObjects)
2542 return logicalHeight;
2543
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002544 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2545}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002546
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002547LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2548{
2549 if (!m_floatingObjects)
2550 return logicalHeight;
2551
2552 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002553}
2554
2555LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2556{
2557 if (!m_floatingObjects)
2558 return 0;
2559 LayoutUnit lowestFloatBottom = 0;
2560 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2561 auto end = floatingObjectSet.end();
2562 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2563 FloatingObject* floatingObject = it->get();
2564 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
andersca@apple.com86298632013-11-10 19:32:33 +00002565 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002566 }
2567 return lowestFloatBottom;
2568}
2569
hyatt@apple.com87515262014-09-04 21:20:12 +00002570LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2571{
2572 if (!m_floatingObjects)
2573 return 0;
2574 LayoutUnit lowestFloatBottom = 0;
2575 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2576 auto end = floatingObjectSet.end();
2577 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2578 FloatingObject* floatingObject = it->get();
2579 if (floatingObject->isPlaced() && floatingObject->renderer().style().styleType() == FIRST_LETTER && floatingObject->renderer().style().initialLetterDrop() > 0)
2580 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2581 }
2582 return lowestFloatBottom;
2583}
2584
weinig@apple.com12840dc2013-10-22 23:59:08 +00002585LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002586{
2587 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002588 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002589 return 0;
2590
weinig@apple.com12840dc2013-10-22 23:59:08 +00002591 LayoutUnit childLogicalTop = child.logicalTop();
2592 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002593 LayoutUnit lowestFloatLogicalBottom = 0;
2594
2595 // Floats that will remain the child's responsibility to paint should factor into its
2596 // overflow.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002597 auto childEnd = child.m_floatingObjects->set().end();
2598 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002599 FloatingObject* floatingObject = childIt->get();
andersca@apple.com86298632013-11-10 19:32:33 +00002600 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002601 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002602 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002603
2604 if (logicalBottom > logicalHeight()) {
2605 // If the object is not in the list, we add it now.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002606 if (!containsFloat(floatingObject->renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002607 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2608 bool shouldPaint = false;
2609
2610 // The nearest enclosing layer always paints the float (so that zindex and stacking
2611 // behaves properly). We always want to propagate the desire to paint the float as
2612 // far out as we can, to the outermost block that overlaps the float, stopping only
2613 // if we hit a self-painting layer boundary.
2614 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2615 floatingObject->setShouldPaint(false);
2616 shouldPaint = true;
2617 }
2618 // We create the floating object list lazily.
2619 if (!m_floatingObjects)
2620 createFloatingObjects();
2621
2622 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2623 }
2624 } else {
2625 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
weinig@apple.com12840dc2013-10-22 23:59:08 +00002626 && floatingObject->renderer().isDescendantOf(&child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002627 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2628 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2629 // layer.
2630 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2631 // it should paint.
2632 floatingObject->setShouldPaint(true);
2633 }
2634
2635 // 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
2636 // child now.
2637 if (floatingObject->isDescendant())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002638 child.addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002639 }
2640 }
2641 return lowestFloatLogicalBottom;
2642}
2643
weinig@apple.com12840dc2013-10-22 23:59:08 +00002644bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002645{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002646 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002647 return false;
2648
2649 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002650 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002651 if (it == floatingObjectSet.end())
2652 return false;
2653
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002654 return logicalBottomForFloat(it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002655}
2656
2657void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
2658{
2659 ASSERT(!avoidsFloats());
2660
2661 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2662 if (!prev->m_floatingObjects)
2663 return;
2664
2665 logicalLeftOffset += marginLogicalLeft();
2666
2667 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2668 auto prevEnd = prevSet.end();
2669 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2670 FloatingObject* floatingObject = prevIt->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002671 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002672 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2673 // We create the floating object list lazily.
2674 if (!m_floatingObjects)
2675 createFloatingObjects();
2676
2677 // Applying the child's margin makes no sense in the case where the child was passed in.
2678 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2679 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2680 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2681 // will get applied twice.
2682 LayoutSize offset = isHorizontalWritingMode()
2683 ? LayoutSize(logicalLeftOffset - (prev != parent() ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2684 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != parent() ? prev->marginTop() : LayoutUnit()));
2685
2686 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2687 }
2688 }
2689 }
2690}
2691
2692void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2693{
2694 if (!everHadLayout() && !containsFloats())
2695 return;
2696
2697 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2698 setChildNeedsLayout(markParents);
2699
2700 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002701 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002702
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002703 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002704 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2705 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2706 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002707 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002708 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2709 block.setChildNeedsLayout(markParents);
2710 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002711 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002712 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002713 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2714 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002715 }
2716}
2717
2718void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2719{
2720 if (!m_floatingObjects)
2721 return;
2722
2723 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2724 auto end = floatingObjectSet.end();
2725
2726 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
cdumez@apple.come9437792014-10-08 23:33:43 +00002727 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned() || downcast<RenderBlockFlow>(*next).avoidsFloats())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002728 continue;
2729
cdumez@apple.come9437792014-10-08 23:33:43 +00002730 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002731 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002732 RenderBox& floatingBox = (*it)->renderer();
2733 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002734 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002735 if (nextBlock.containsFloat(floatingBox))
2736 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002737 }
2738 }
2739}
2740
weinig@apple.com31324fd2013-10-28 19:22:51 +00002741LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2742{
akling@apple.com827be9c2013-10-29 02:58:43 +00002743 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002744 return point;
2745
2746 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2747 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2748 // case.
2749 if (isHorizontalWritingMode())
2750 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2751 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2752}
2753
weinig@apple.com12840dc2013-10-22 23:59:08 +00002754LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002755{
2756 // There is no need to compute clearance if we have no floats.
2757 if (!containsFloats())
2758 return 0;
2759
2760 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002761 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002762 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002763 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002764 case CNONE:
2765 break;
2766 case CLEFT:
2767 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2768 break;
2769 case CRIGHT:
2770 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2771 break;
2772 case CBOTH:
2773 logicalBottom = lowestFloatLogicalBottom();
2774 break;
2775 }
2776
2777 // 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 +00002778 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002779 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002780 LayoutUnit newLogicalTop = logicalTop;
2781 while (true) {
2782 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2783 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2784 return newLogicalTop - logicalTop;
2785
2786 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002787 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002788 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2789
2790 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002791 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2792 LayoutUnit childOldMarginLeft = child.marginLeft();
2793 LayoutUnit childOldMarginRight = child.marginRight();
2794 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002795
weinig@apple.com12840dc2013-10-22 23:59:08 +00002796 child.setLogicalTop(newLogicalTop);
2797 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002798 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002799 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002800 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2801
weinig@apple.com12840dc2013-10-22 23:59:08 +00002802 child.setLogicalTop(childOldLogicalTop);
2803 child.setLogicalWidth(childOldLogicalWidth);
2804 child.setMarginLeft(childOldMarginLeft);
2805 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002806
2807 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2808 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2809 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2810 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2811 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002812 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002813 return newLogicalTop - logicalTop;
2814 }
2815
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002816 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002817 ASSERT(newLogicalTop >= logicalTop);
2818 if (newLogicalTop < logicalTop)
2819 break;
2820 }
2821 ASSERT_NOT_REACHED();
2822 }
2823 return result;
2824}
2825
2826bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2827{
2828 if (!m_floatingObjects)
2829 return false;
2830
2831 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002832 if (is<RenderView>(*this))
2833 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002834
2835 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2836 auto begin = floatingObjectSet.begin();
2837 for (auto it = floatingObjectSet.end(); it != begin;) {
2838 --it;
2839 FloatingObject* floatingObject = it->get();
2840 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2841 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2842 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2843 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2844 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2845 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2846 return true;
2847 }
2848 }
2849 }
2850
2851 return false;
2852}
2853
weinig@apple.com611b9292013-10-20 22:57:54 +00002854bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2855{
2856 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002857
darin@apple.come1be6ca2014-04-28 04:19:10 +00002858 if (auto simpleLineLayout = this->simpleLineLayout())
2859 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002860
weinig@apple.com611b9292013-10-20 22:57:54 +00002861 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2862}
2863
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002864void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2865{
akling@apple.com827be9c2013-10-29 02:58:43 +00002866 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002867 return;
2868
2869 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2870 // for either overflow or translations via relative positioning.
2871 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002872 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2873
weinig@apple.com611b9292013-10-20 22:57:54 +00002874 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
2875 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002876 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002877 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002878 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002879 }
2880 } else {
2881 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2882 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002883 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2884 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002885 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002886 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002887 left = std::min(left, x + obj->x());
2888 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002889 }
2890 }
2891 }
2892 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002893
2894 if (m_floatingObjects) {
2895 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2896 auto end = floatingObjectSet.end();
2897 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2898 FloatingObject* r = it->get();
2899 // Only examine the object if our m_shouldPaint flag is set.
2900 if (r->shouldPaint()) {
2901 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2902 LayoutUnit floatRight = floatLeft + r->renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002903 left = std::min(left, floatLeft);
2904 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002905 }
2906 }
2907 }
2908}
2909
2910void RenderBlockFlow::fitBorderToLinesIfNeeded()
2911{
akling@apple.com827be9c2013-10-29 02:58:43 +00002912 if (style().borderFit() == BorderFitBorder || hasOverrideWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002913 return;
2914
2915 // Walk any normal flow lines to snugly fit.
2916 LayoutUnit left = LayoutUnit::max();
2917 LayoutUnit right = LayoutUnit::min();
2918 LayoutUnit oldWidth = contentWidth();
2919 adjustForBorderFit(0, left, right);
2920
2921 // Clamp to our existing edges. We can never grow. We only shrink.
2922 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2923 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002924 left = std::min(rightEdge, std::max(leftEdge, left));
2925 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002926
2927 LayoutUnit newContentWidth = right - left;
2928 if (newContentWidth == oldWidth)
2929 return;
2930
2931 setOverrideLogicalContentWidth(newContentWidth);
2932 layoutBlock(false);
2933 clearOverrideLogicalContentWidth();
2934}
2935
2936void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2937{
2938 if (logicalTop >= logicalBottom)
2939 return;
2940
antti@apple.combe9d3e12014-05-11 09:42:47 +00002941 // Floats currently affect the choice whether to use simple line layout path.
2942 if (m_simpleLineLayout) {
2943 invalidateLineLayoutPath();
2944 return;
2945 }
2946
weinig@apple.com611b9292013-10-20 22:57:54 +00002947 RootInlineBox* lowestDirtyLine = lastRootBox();
2948 RootInlineBox* afterLowest = lowestDirtyLine;
2949 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2950 afterLowest = lowestDirtyLine;
2951 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2952 }
2953
2954 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2955 afterLowest->markDirty();
2956 afterLowest = afterLowest->prevRootBox();
2957 }
2958}
2959
antti@apple.com0e632aa2013-10-22 21:03:38 +00002960int RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00002961{
2962 if (isWritingModeRoot() && !isRubyRun())
2963 return -1;
2964
2965 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00002966 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00002967
antti@apple.com940f5872013-10-24 20:31:11 +00002968 if (!hasLines())
2969 return -1;
weinig@apple.com611b9292013-10-20 22:57:54 +00002970
darin@apple.come1be6ca2014-04-28 04:19:10 +00002971 if (auto simpleLineLayout = this->simpleLineLayout())
2972 return SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00002973
akling@apple.comee3c8df2013-11-06 08:09:44 +00002974 ASSERT(firstRootBox());
2975 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00002976}
2977
2978int RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
2979{
2980 if (isWritingModeRoot() && !isRubyRun())
2981 return -1;
2982
2983 if (!childrenInline())
2984 return RenderBlock::inlineBlockBaseline(lineDirection);
2985
antti@apple.com0e632aa2013-10-22 21:03:38 +00002986 if (!hasLines()) {
2987 if (!hasLineIfEmpty())
2988 return -1;
akling@apple.com827be9c2013-10-29 02:58:43 +00002989 const FontMetrics& fontMetrics = firstLineStyle().fontMetrics();
weinig@apple.com611b9292013-10-20 22:57:54 +00002990 return fontMetrics.ascent()
2991 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
2992 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
2993 }
2994
darin@apple.come1be6ca2014-04-28 04:19:10 +00002995 if (auto simpleLineLayout = this->simpleLineLayout())
2996 return SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00002997
akling@apple.comee3c8df2013-11-06 08:09:44 +00002998 bool isFirstLine = lastRootBox() == firstRootBox();
akling@apple.com827be9c2013-10-29 02:58:43 +00002999 const RenderStyle& style = isFirstLine ? firstLineStyle() : this->style();
akling@apple.comee3c8df2013-11-06 08:09:44 +00003000 return lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003001}
3002
weinig@apple.com12840dc2013-10-22 23:59:08 +00003003GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003004 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3005{
antti@apple.comfea51992013-10-28 13:39:23 +00003006 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003007
weinig@apple.com611b9292013-10-20 22:57:54 +00003008 GapRects result;
3009
3010 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3011
antti@apple.com0e632aa2013-10-22 21:03:38 +00003012 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003013 if (containsStart) {
3014 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
3015 // case.
3016 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3017 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3018 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3019 }
3020 return result;
3021 }
3022
3023 RootInlineBox* lastSelectedLine = 0;
3024 RootInlineBox* curr;
3025 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3026
3027 // Now paint the gaps for the lines.
3028 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3029 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3030 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3031
3032 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003033 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003034 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3035
3036 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3037 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003038 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003039 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3040 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3041 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3042
3043 lastSelectedLine = curr;
3044 }
3045
3046 if (containsStart && !lastSelectedLine)
3047 // VisibleSelection must start just after our last line.
3048 lastSelectedLine = lastRootBox();
3049
3050 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3051 // Go ahead and update our lastY to be the bottom of the last selected line.
3052 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3053 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3054 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3055 }
3056 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003057}
3058
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003059void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3060{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003061 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003062 return;
3063
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003064 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3065 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003066 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003067 flowFragment->initializeStyle();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003068 setRenderNamedFlowFragment(flowFragment);
3069 addChild(renderNamedFlowFragment());
3070 }
3071}
3072
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003073bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3074{
3075 // A block without floats or that expands to enclose them won't need a relayout
3076 // after a region range change. There is no overflow content needing relayout
3077 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003078 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003079 return false;
3080
3081 return true;
3082}
3083
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003084bool RenderBlockFlow::canHaveChildren() const
3085{
3086 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3087}
3088
3089bool RenderBlockFlow::canHaveGeneratedChildren() const
3090{
3091 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3092}
3093
3094bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3095{
3096 if (!isRenderNamedFlowFragmentContainer())
3097 return false;
3098
3099 return hasRelativeLogicalHeight() && !isRenderView();
3100}
3101
3102void RenderBlockFlow::updateLogicalHeight()
3103{
3104 RenderBlock::updateLogicalHeight();
3105
abucur@adobe.comfad53712014-05-06 17:30:40 +00003106 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003107 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003108 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3109 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003110}
3111
3112void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3113{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003114 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003115 if (rareData.m_renderNamedFlowFragment)
3116 rareData.m_renderNamedFlowFragment->destroy();
3117 rareData.m_renderNamedFlowFragment = flowFragment;
3118}
3119
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003120void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3121{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003122 if (flowThread || hasRareBlockFlowData()) {
3123 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3124 rareData.m_multiColumnFlowThread = flowThread;
3125 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003126}
3127
akling@apple.com525dae62014-01-03 20:22:09 +00003128static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003129{
akling@apple.com38f0a652014-02-06 21:24:17 +00003130 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003131}
3132
3133RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3134{
3135 ASSERT(i >= 0);
3136
akling@apple.com827be9c2013-10-29 02:58:43 +00003137 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003138 return nullptr;
3139
3140 if (childrenInline()) {
3141 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3142 if (!i--)
3143 return box;
3144 }
akling@apple.com525dae62014-01-03 20:22:09 +00003145 return nullptr;
3146 }
3147
3148 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3149 if (!shouldCheckLines(blockFlow))
3150 continue;
3151 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3152 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003153 }
3154
3155 return nullptr;
3156}
3157
3158int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3159{
akling@apple.com827be9c2013-10-29 02:58:43 +00003160 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003161 return 0;
3162
3163 int count = 0;
3164
3165 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003166 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003167 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003168 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003169 }
weinig@apple.com17140912013-10-19 19:55:40 +00003170 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3171 count++;
3172 if (box == stopRootInlineBox) {
3173 if (found)
3174 *found = true;
3175 break;
3176 }
3177 }
akling@apple.com525dae62014-01-03 20:22:09 +00003178 return count;
3179 }
3180
3181 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3182 if (!shouldCheckLines(blockFlow))
3183 continue;
3184 bool recursiveFound = false;
3185 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3186 if (recursiveFound) {
3187 if (found)
3188 *found = true;
3189 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003190 }
3191 }
3192
3193 return count;
3194}
3195
3196static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3197{
akling@apple.com827be9c2013-10-29 02:58:43 +00003198 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003199 return -1;
3200
3201 if (block.childrenInline()) {
3202 for (auto box = block.firstRootBox(); box; box = box->nextRootBox()) {
3203 if (++count == lineCount)
3204 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3205 }
3206 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003207 RenderBox* normalFlowChildWithoutLines = nullptr;
weinig@apple.com17140912013-10-19 19:55:40 +00003208 for (auto obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003209 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3210 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003211 if (result != -1)
3212 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003213 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003214 normalFlowChildWithoutLines = obj;
3215 }
3216 if (normalFlowChildWithoutLines && !lineCount)
3217 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3218 }
3219
3220 return -1;
3221}
3222
3223int RenderBlockFlow::heightForLineCount(int lineCount)
3224{
3225 int count = 0;
3226 return getHeightForLineCount(*this, lineCount, true, count);
3227}
3228
3229void RenderBlockFlow::clearTruncation()
3230{
akling@apple.com827be9c2013-10-29 02:58:43 +00003231 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003232 return;
3233
3234 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003235 ensureLineBoxes();
3236
weinig@apple.com17140912013-10-19 19:55:40 +00003237 setHasMarkupTruncation(false);
3238 for (auto box = firstRootBox(); box; box = box->nextRootBox())
3239 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003240 return;
3241 }
3242
3243 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3244 if (shouldCheckLines(blockFlow))
3245 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003246 }
3247}
3248
weinig@apple.com3f23b382013-10-19 20:26:58 +00003249bool RenderBlockFlow::containsNonZeroBidiLevel() const
3250{
3251 for (auto root = firstRootBox(); root; root = root->nextRootBox()) {
3252 for (auto box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
3253 if (box->bidiLevel())
3254 return true;
3255 }
3256 }
3257 return false;
3258}
3259
weinig@apple.com611b9292013-10-20 22:57:54 +00003260Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3261{
3262 if (!box)
3263 return Position();
3264
3265 if (!box->renderer().nonPseudoNode())
3266 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3267
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003268 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003269 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3270
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003271 auto& textBox = downcast<InlineTextBox>(*box);
3272 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003273}
3274
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003275VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003276{
3277 ASSERT(childrenInline());
3278
antti@apple.com940f5872013-10-24 20:31:11 +00003279 ensureLineBoxes();
3280
weinig@apple.com611b9292013-10-20 22:57:54 +00003281 if (!firstRootBox())
3282 return createVisiblePosition(0, DOWNSTREAM);
3283
akling@apple.com827be9c2013-10-29 02:58:43 +00003284 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3285 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003286
3287 // look for the closest line box in the root box which is at the passed-in y coordinate
3288 InlineBox* closestBox = 0;
3289 RootInlineBox* firstRootBoxWithChildren = 0;
3290 RootInlineBox* lastRootBoxWithChildren = 0;
3291 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003292 if (region && root->containingRegion() != region)
3293 continue;
3294
weinig@apple.com611b9292013-10-20 22:57:54 +00003295 if (!root->firstLeafChild())
3296 continue;
3297 if (!firstRootBoxWithChildren)
3298 firstRootBoxWithChildren = root;
3299
3300 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3301 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3302 break;
3303
3304 lastRootBoxWithChildren = root;
3305
3306 // check if this root line box is located at this y coordinate
3307 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3308 if (linesAreFlipped) {
3309 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3310 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3311 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3312
3313 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3314 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3315 continue;
3316 }
3317 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3318 if (closestBox)
3319 break;
3320 }
3321 }
3322
3323 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3324
3325 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3326 // y coordinate is below last root line box, pretend we hit it
3327 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3328 }
3329
3330 if (closestBox) {
3331 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003332 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003333 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3334 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3335 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3336 if (box->isLineBreak()) {
3337 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3338 box = newBox;
3339 }
3340 // y coordinate is above first root line box, so return the start of the first
3341 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3342 }
3343 }
3344
3345 // pass the box a top position that is inside it
3346 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3347 if (!isHorizontalWritingMode())
3348 point = point.transposedPoint();
3349 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003350 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003351 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003352 }
3353
3354 if (lastRootBoxWithChildren) {
3355 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3356 ASSERT(moveCaretToBoundary);
3357 InlineBox* logicallyLastBox;
3358 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3359 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3360 }
3361
3362 // Can't reach this. We have a root line box, but it has no kids.
3363 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3364 // seems to hit this code path.
3365 return createVisiblePosition(0, DOWNSTREAM);
3366}
3367
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003368VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003369{
3370 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003371 return fragment->positionForPoint(point, region);
3372 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003373}
3374
3375
weinig@apple.com611b9292013-10-20 22:57:54 +00003376void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3377{
antti@apple.com940f5872013-10-24 20:31:11 +00003378 ASSERT(childrenInline());
3379
3380 ensureLineBoxes();
3381
weinig@apple.com611b9292013-10-20 22:57:54 +00003382 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003383 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3384 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003385 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3386 if (!rect.isEmpty())
zalan@apple.com376339c2014-08-28 04:24:31 +00003387 rects.append(snappedIntRect(rect));
weinig@apple.com611b9292013-10-20 22:57:54 +00003388 }
3389}
3390
3391void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3392{
3393 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003394
darin@apple.come1be6ca2014-04-28 04:19:10 +00003395 if (auto simpleLineLayout = this->simpleLineLayout()) {
3396 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003397 return;
3398 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003399 m_lineBoxes.paint(this, paintInfo, paintOffset);
3400}
3401
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003402bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003403{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003404 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003405 return false;
3406
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003407 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003408 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3409
3410 bool needsRelayout;
3411 bool neededRelayout = false;
3412 bool firstPass = true;
3413 do {
3414 // Column heights may change here because of balancing. We may have to do multiple layout
3415 // passes, depending on how the contents is fitted to the changed column heights. In most
3416 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3417 // passes than that, though, but the number of retries should not exceed the number of
3418 // columns, unless we have a bug.
3419 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003420 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3421 if (multicolSet->recalculateColumnHeight(firstPass))
3422 needsRelayout = true;
3423 if (needsRelayout) {
3424 // Once a column set gets a new column height, that column set and all successive column
3425 // sets need to be laid out over again, since their logical top will be affected by
3426 // this, and therefore their column heights may change as well, at least if the multicol
3427 // height is constrained.
3428 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003429 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003430 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003431 if (needsRelayout) {
3432 // Layout again. Column balancing resulted in a new height.
3433 neededRelayout = true;
3434 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3435 setChildNeedsLayout(MarkOnlyThis);
3436 if (firstPass)
3437 statePusher.pop();
3438 layoutBlock(false);
3439 }
3440 firstPass = false;
3441 } while (needsRelayout);
3442
3443 multiColumnFlowThread()->setInBalancingPass(false);
3444
3445 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003446}
3447
antti@apple.com940f5872013-10-24 20:31:11 +00003448bool RenderBlockFlow::hasLines() const
3449{
3450 ASSERT(childrenInline());
3451
darin@apple.come1be6ca2014-04-28 04:19:10 +00003452 if (auto simpleLineLayout = this->simpleLineLayout())
3453 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003454
3455 return lineBoxes().firstLineBox();
3456}
3457
antti@apple.com9e891c82014-05-22 06:12:34 +00003458void RenderBlockFlow::invalidateLineLayoutPath()
3459{
3460 switch (m_lineLayoutPath) {
3461 case UndeterminedPath:
3462 case ForceLineBoxesPath:
3463 ASSERT(!m_simpleLineLayout);
3464 return;
3465 case LineBoxesPath:
3466 ASSERT(!m_simpleLineLayout);
3467 m_lineLayoutPath = UndeterminedPath;
3468 return;
3469 case SimpleLinesPath:
3470 // The simple line layout may have become invalid.
3471 m_simpleLineLayout = nullptr;
3472 setNeedsLayout();
3473 m_lineLayoutPath = UndeterminedPath;
3474 return;
3475 }
3476 ASSERT_NOT_REACHED();
3477}
3478
antti@apple.com940f5872013-10-24 20:31:11 +00003479void RenderBlockFlow::layoutSimpleLines(LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
3480{
3481 ASSERT(!m_lineBoxes.firstLineBox());
3482
antti@apple.comfea51992013-10-28 13:39:23 +00003483 m_simpleLineLayout = SimpleLineLayout::create(*this);
antti@apple.com940f5872013-10-24 20:31:11 +00003484
antti@apple.comfea51992013-10-28 13:39:23 +00003485 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003486 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
3487
3488 repaintLogicalTop = lineLayoutTop;
3489 repaintLogicalBottom = lineLayoutTop + lineLayoutHeight;
3490
3491 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3492}
3493
3494void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3495{
antti@apple.com42fb53d2013-10-25 02:33:11 +00003496 ASSERT(m_lineLayoutPath == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003497 lineBoxes().deleteLineBoxes();
zalan@apple.com29a2eb62014-11-20 18:11:07 +00003498 ASSERT(!childrenOfType<RenderElement>(*this).first());
3499 for (auto& textRenderer : childrenOfType<RenderText>(*this))
3500 textRenderer.deleteLineBoxesBeforeSimpleLineLayout();
antti@apple.com940f5872013-10-24 20:31:11 +00003501}
3502
3503void RenderBlockFlow::ensureLineBoxes()
3504{
antti@apple.com42fb53d2013-10-25 02:33:11 +00003505 m_lineLayoutPath = ForceLineBoxesPath;
antti@apple.comfea51992013-10-28 13:39:23 +00003506 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003507 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003508 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003509
3510#if !ASSERT_DISABLED
3511 LayoutUnit oldHeight = logicalHeight();
3512#endif
3513 bool didNeedLayout = needsLayout();
3514
3515 bool relayoutChildren = false;
3516 LayoutUnit repaintLogicalTop;
3517 LayoutUnit repaintLogicalBottom;
3518 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3519
3520 updateLogicalHeight();
3521 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3522
3523 if (!didNeedLayout)
3524 clearNeedsLayout();
3525}
3526
weinig@apple.com611b9292013-10-20 22:57:54 +00003527#ifndef NDEBUG
zalan@apple.comfac337f2014-08-29 17:55:34 +00003528void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003529{
weinig@apple.com611b9292013-10-20 22:57:54 +00003530 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003531 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003532
3533 if (auto simpleLineLayout = this->simpleLineLayout())
3534 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003535}
3536#endif
3537
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003538RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3539{
3540 if (hasRareBlockFlowData())
3541 return *m_rareBlockFlowData;
3542 materializeRareBlockFlowData();
3543 return *m_rareBlockFlowData;
3544}
3545
3546void RenderBlockFlow::materializeRareBlockFlowData()
3547{
3548 ASSERT(!hasRareBlockFlowData());
3549 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3550}
3551
aestes@apple.com6751d842014-01-12 02:51:25 +00003552#if ENABLE(IOS_TEXT_AUTOSIZING)
3553inline static bool isVisibleRenderText(RenderObject* renderer)
3554{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003555 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003556 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003557 RenderText& renderText = downcast<RenderText>(*renderer);
3558 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003559}
3560
3561inline static bool resizeTextPermitted(RenderObject* render)
3562{
3563 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3564 auto renderer = render->parent();
3565 while (renderer) {
3566 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003567 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003568 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003569 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003570 }
3571 renderer = renderer->parent();
3572 }
3573 return true;
3574}
3575
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003576int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003577{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003578 if (style().visibility() != VISIBLE)
3579 return 0;
3580 if (childrenInline())
3581 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003582 // Only descend into list items.
3583 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003584 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3585 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003586 return count;
3587}
3588
3589static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3590{
3591 if (!render->isRenderBlock())
3592 return true;
3593 if (render->isListItem())
3594 return render->style().height().type() != Fixed;
3595 return false;
3596}
3597
3598// For now, we auto size single lines of text the same as multiple lines.
3599// We've been experimenting with low values for single lines of text.
3600static inline float oneLineTextMultiplier(float specifiedSize)
3601{
3602 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3603}
3604
3605static inline float textMultiplier(float specifiedSize)
3606{
3607 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3608}
3609
3610void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3611{
3612 // Don't do any work if the block is smaller than the visible area.
3613 if (visibleWidth >= width())
3614 return;
3615
3616 unsigned lineCount;
3617 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003618 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003619 if (!count)
3620 lineCount = NO_LINE;
3621 else if (count == 1)
3622 lineCount = ONE_LINE;
3623 else
3624 lineCount = MULTI_LINE;
3625 } else
3626 lineCount = m_lineCountForTextAutosizing;
3627
3628 ASSERT(lineCount != NOT_SET);
3629 if (lineCount == NO_LINE)
3630 return;
3631
3632 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3633 float scale = visibleWidth / actualWidth;
3634 float minFontSize = roundf(size / scale);
3635
3636 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3637 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003638 RenderText& text = downcast<RenderText>(*descendent);
3639 RenderStyle& oldStyle = text.style();
aestes@apple.com6751d842014-01-12 02:51:25 +00003640 FontDescription fontDescription = oldStyle.fontDescription();
3641 float specifiedSize = fontDescription.specifiedSize();
3642 float scaledSize = roundf(specifiedSize * scale);
3643 if (scaledSize > 0 && scaledSize < minFontSize) {
3644 // 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.
3645 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3646 if (m_lineCountForTextAutosizing == NOT_SET)
3647 m_lineCountForTextAutosizing = lineCount;
3648 if (m_widthForTextAutosizing == -1)
3649 m_widthForTextAutosizing = actualWidth;
3650
3651 float candidateNewSize = 0;
3652 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3653 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003654 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3655 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003656 }
3657 }
3658 }
3659}
3660#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3661
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003662RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3663{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003664 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3665 if (!flowThread)
3666 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003667
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003668 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003669
3670 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003671 flowThread->setChildNeedsLayout(MarkOnlyThis);
3672
3673 if (flowThread->needsLayout()) {
3674 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3675 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3676
3677 flowThread->invalidateRegions();
3678 flowThread->setNeedsHeightsRecalculation(true);
3679 flowThread->layout();
3680 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003681 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3682 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3683 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3684 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3685 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3686 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3687 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3688 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003689 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003690 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003691 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003692
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003693 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003694}
3695
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003696void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3697{
3698 if (multiColumnFlowThread())
3699 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003700 if (beforeChild) {
3701 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3702 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3703 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003704 RenderBlock::addChild(newChild, beforeChild);
3705}
3706
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003707void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003708{
3709 if (!documentBeingDestroyed()) {
3710 RenderFlowThread* flowThread = multiColumnFlowThread();
3711 if (flowThread && flowThread != &oldChild)
3712 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3713 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003714 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003715}
3716
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003717void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003718{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003719 // If we don't use columns or flow threads, then bail.
3720 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003721 return;
3722
3723 // 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 +00003724 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3725 LogicalExtentComputedValues computedValues;
3726 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3727 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003728 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003729 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003730 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3731 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003732 } else if (is<RenderFlowThread>(*this)) {
3733 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003734
3735 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3736 // is known. The page logical height thing in LayoutState is meaningless for flow
3737 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3738 // thread), but as long as it is used universally as a means to determine whether page
3739 // height is known or not, we need this. Page height is unknown when column balancing is
3740 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3741 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3742 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3743 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003744 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003745
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003746 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003747 }
3748}
3749
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003750bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3751{
3752 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3753 // in the RenderView instead.
3754 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isRoot() || isBody());
3755
3756 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3757}
3758
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003759void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3760{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003761 bool destroyColumns = !requiresColumns(count);
3762 if (destroyColumns) {
3763 if (multiColumnFlowThread())
3764 destroyMultiColumnFlowThread();
3765 } else {
3766 if (!multiColumnFlowThread())
3767 createMultiColumnFlowThread();
3768 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003769 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3770 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003771 }
3772}
3773
cdumez@apple.com78141732014-11-04 23:00:48 +00003774void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003775{
hyatt@apple.com86919862014-01-27 16:27:45 +00003776 if (!multiColumnFlowThread())
3777 return;
3778
3779 bool needsLayout = false;
3780 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003781 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003782 if (oldProgressionIsInline != newProgressionIsInline) {
3783 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3784 needsLayout = true;
3785 }
3786
3787 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003788 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003789 if (oldProgressionIsReversed != newProgressionIsReversed) {
3790 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3791 needsLayout = true;
3792 }
3793
3794 if (needsLayout)
3795 setNeedsLayoutAndPrefWidthsRecalc();
3796}
3797
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003798LayoutUnit RenderBlockFlow::computedColumnWidth() const
3799{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003800 if (multiColumnFlowThread())
3801 return multiColumnFlowThread()->computedColumnWidth();
3802 return contentLogicalWidth();
3803}
3804
3805unsigned RenderBlockFlow::computedColumnCount() const
3806{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003807 if (multiColumnFlowThread())
3808 return multiColumnFlowThread()->computedColumnCount();
3809
3810 return 1;
3811}
3812
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003813bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3814{
3815 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3816 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3817 return hasTopOverflow;
3818
3819 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3820 hasTopOverflow = !hasTopOverflow;
3821
3822 return hasTopOverflow;
3823}
3824
3825bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3826{
3827 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3828 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3829 return hasLeftOverflow;
3830
3831 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3832 hasLeftOverflow = !hasLeftOverflow;
3833
3834 return hasLeftOverflow;
3835}
3836
zalan@apple.comac6956c2014-09-05 14:18:06 +00003837struct InlineMinMaxIterator {
3838/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3839 inline min/max width calculations. Note the following about the way it walks:
3840 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3841 (2) We do not drill into the children of floats or replaced elements, since you can't break
3842 in the middle of such an element.
3843 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3844 distinct borders/margin/padding that contribute to the min/max width.
3845*/
3846 const RenderBlockFlow& parent;
3847 RenderObject* current;
3848 bool endOfInline;
3849 bool initial;
3850
3851 InlineMinMaxIterator(const RenderBlockFlow& p)
3852 : parent(p)
3853 , current(nullptr)
3854 , endOfInline(false)
3855 , initial(true)
3856 { }
3857
3858 RenderObject* next();
3859};
3860
3861RenderObject* InlineMinMaxIterator::next()
3862{
3863 RenderObject* result = nullptr;
3864 bool oldEndOfInline = endOfInline;
3865 endOfInline = false;
3866 do {
3867 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3868 result = current->firstChildSlow();
3869 else if (initial) {
3870 result = parent.firstChild();
3871 initial = false;
3872 }
3873
3874 if (!result) {
3875 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3876 if (!oldEndOfInline && current && current->isRenderInline()) {
3877 result = current;
3878 endOfInline = true;
3879 break;
3880 }
3881
3882 while (current && current != &parent) {
3883 result = current->nextSibling();
3884 if (result)
3885 break;
3886 current = current->parent();
3887 if (current && current != &parent && current->isRenderInline()) {
3888 result = current;
3889 endOfInline = true;
3890 break;
3891 }
3892 }
3893 }
3894
3895 if (!result)
3896 break;
3897
3898 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3899 break;
3900
3901 current = result;
3902 result = nullptr;
3903 } while (current || current == &parent);
3904 // Update our position.
3905 current = result;
3906 return result;
3907}
3908
3909static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3910{
3911 if (cssUnit.type() != Auto)
3912 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
3913 return 0;
3914}
3915
3916static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
3917{
3918 const RenderStyle& childStyle = child.style();
3919 if (endOfInline) {
3920 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
3921 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
3922 child.borderEnd();
3923 }
3924 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
3925 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
3926 child.borderStart();
3927}
3928
3929static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
3930{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003931 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00003932 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003933 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00003934 const UChar space = ' ';
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003935 const Font& font = renderText.style().font(); // FIXME: This ignores first-line.
3936 float spaceWidth = font.width(RenderBlock::constructTextRun(&renderText, font, &space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00003937 inlineMax -= spaceWidth + font.wordSpacing();
3938 if (inlineMin > inlineMax)
3939 inlineMin = inlineMax;
3940 }
3941}
3942
3943static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
3944{
3945 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
3946}
3947
3948void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3949{
3950 float inlineMax = 0;
3951 float inlineMin = 0;
3952
3953 const RenderStyle& styleToUse = style();
3954 RenderBlock* containingBlock = this->containingBlock();
3955 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
3956
3957 // If we are at the start of a line, we want to ignore all white-space.
3958 // Also strip spaces if we previously had text that ended in a trailing space.
3959 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003960 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00003961
3962 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
3963 // very specific cirucumstances (in order to match common WinIE renderings).
3964 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
3965 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
3966
cdumez@apple.comc28103d52014-10-31 23:25:05 +00003967 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00003968
3969 InlineMinMaxIterator childIterator(*this);
3970
3971 // Only gets added to the max preffered width once.
3972 bool addedTextIndent = false;
3973 // Signals the text indent was more negative than the min preferred width
3974 bool hasRemainingNegativeTextIndent = false;
3975
3976 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
3977 RenderObject* prevFloat = 0;
3978 bool isPrevChildInlineFlow = false;
3979 bool shouldBreakLineAfterText = false;
3980 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00003981 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00003982 child->style().autoWrap();
3983
3984 if (!child->isBR()) {
3985 // Step One: determine whether or not we need to go ahead and
3986 // terminate our current line. Each discrete chunk can become
3987 // the new min-width, if it is the widest chunk seen so far, and
3988 // it can also become the max-width.
3989
3990 // Children fall into three categories:
3991 // (1) An inline flow object. These objects always have a min/max of 0,
3992 // and are included in the iteration solely so that their margins can
3993 // be added in.
3994 //
3995 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
3996 // These objects can always be on a line by themselves, so in this situation
3997 // we need to go ahead and break the current line, and then add in our own
3998 // margins and min/max width on its own line, and then terminate the line.
3999 //
4000 // (3) A text object. Text runs can have breakable characters at the start,
4001 // the middle or the end. They may also lose whitespace off the front if
4002 // we're already ignoring whitespace. In order to compute accurate min-width
4003 // information, we need three pieces of information.
4004 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4005 // starts with whitespace.
4006 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4007 // ends with whitespace.
4008 // (c) the min/max width of the string (trimmed for whitespace).
4009 //
4010 // If the text string starts with whitespace, then we need to go ahead and
4011 // terminate our current line (unless we're already in a whitespace stripping
4012 // mode.
4013 //
4014 // If the text string has a breakable character in the middle, but didn't start
4015 // with whitespace, then we add the width of the first non-breakable run and
4016 // then end the current line. We then need to use the intermediate min/max width
4017 // values (if any of them are larger than our current min/max). We then look at
4018 // the width of the last non-breakable run and use that to start a new line
4019 // (unless we end in whitespace).
4020 const RenderStyle& childStyle = child->style();
4021 float childMin = 0;
4022 float childMax = 0;
4023
4024 if (!child->isText()) {
4025 if (child->isLineBreakOpportunity()) {
4026 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4027 inlineMin = 0;
4028 continue;
4029 }
4030 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004031 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004032 // Add in padding/border/margin from the appropriate side of
4033 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004034 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004035 childMin += bpm;
4036 childMax += bpm;
4037
4038 inlineMin += childMin;
4039 inlineMax += childMax;
4040
4041 child->setPreferredLogicalWidthsDirty(false);
4042 } else {
4043 // Inline replaced elts add in their margins to their min/max values.
4044 LayoutUnit margins = 0;
4045 Length startMargin = childStyle.marginStart();
4046 Length endMargin = childStyle.marginEnd();
4047 if (startMargin.isFixed())
4048 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4049 if (endMargin.isFixed())
4050 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4051 childMin += margins.ceilToFloat();
4052 childMax += margins.ceilToFloat();
4053 }
4054 }
4055
cdumez@apple.comf8022152014-10-15 00:29:51 +00004056 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004057 // Case (2). Inline replaced elements and floats.
4058 // Go ahead and terminate the current line as far as
4059 // minwidth is concerned.
4060 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4061 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4062
4063 bool clearPreviousFloat;
4064 if (child->isFloating()) {
4065 clearPreviousFloat = (prevFloat
4066 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4067 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4068 prevFloat = child;
4069 } else
4070 clearPreviousFloat = false;
4071
4072 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4073 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
4074 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4075 inlineMin = 0;
4076 }
4077
4078 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4079 if (clearPreviousFloat) {
4080 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4081 inlineMax = 0;
4082 }
4083
4084 // Add in text-indent. This is added in only once.
4085 if (!addedTextIndent && !child->isFloating()) {
4086 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4087 childMin += ceiledIndent;
4088 childMax += ceiledIndent;
4089
4090 if (childMin < 0)
4091 textIndent = LayoutUnit::fromFloatCeil(childMin);
4092 else
4093 addedTextIndent = true;
4094 }
4095
4096 // Add our width to the max.
4097 inlineMax += std::max<float>(0, childMax);
4098
4099 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
4100 if (child->isFloating())
4101 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4102 else
4103 inlineMin += childMin;
4104 } else {
4105 // Now check our line.
4106 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4107
4108 // Now start a new line.
4109 inlineMin = 0;
4110 }
4111
4112 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4113 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4114 inlineMin = 0;
4115 }
4116
4117 // We are no longer stripping whitespace at the start of a line.
4118 if (!child->isFloating()) {
4119 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004120 trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004121 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004122 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004123 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004124 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004125
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004126 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4127 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004128
4129 // Determine if we have a breakable character. Pass in
4130 // whether or not we should ignore any spaces at the front
4131 // of the string. If those are going to be stripped out,
4132 // then they shouldn't be considered in the breakable char
4133 // check.
4134 bool hasBreakableChar, hasBreak;
4135 float beginMin, endMin;
4136 bool beginWS, endWS;
4137 float beginMax, endMax;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004138 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004139 hasBreakableChar, hasBreak, beginMax, endMax,
4140 childMin, childMax, stripFrontSpaces);
4141
4142 // This text object will not be rendered, but it may still provide a breaking opportunity.
4143 if (!hasBreak && !childMax) {
4144 if (autoWrap && (beginWS || endWS)) {
4145 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4146 inlineMin = 0;
4147 }
4148 continue;
4149 }
4150
4151 if (stripFrontSpaces)
4152 trailingSpaceChild = child;
4153 else
4154 trailingSpaceChild = 0;
4155
4156 // Add in text-indent. This is added in only once.
4157 float ti = 0;
4158 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4159 ti = textIndent.ceilToFloat();
4160 childMin += ti;
4161 beginMin += ti;
4162
4163 // It the text indent negative and larger than the child minimum, we re-use the remainder
4164 // in future minimum calculations, but using the negative value again on the maximum
4165 // will lead to under-counting the max pref width.
4166 if (!addedTextIndent) {
4167 childMax += ti;
4168 beginMax += ti;
4169 addedTextIndent = true;
4170 }
4171
4172 if (childMin < 0) {
4173 textIndent = childMin;
4174 hasRemainingNegativeTextIndent = true;
4175 }
4176 }
4177
4178 // If we have no breakable characters at all,
4179 // then this is the easy case. We add ourselves to the current
4180 // min and max and continue.
4181 if (!hasBreakableChar)
4182 inlineMin += childMin;
4183 else {
4184 // We have a breakable character. Now we need to know if
4185 // we start and end with whitespace.
4186 if (beginWS) {
4187 // Go ahead and end the current line.
4188 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4189 } else {
4190 inlineMin += beginMin;
4191 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4192 childMin -= ti;
4193 }
4194
4195 inlineMin = childMin;
4196
4197 if (endWS) {
4198 // We end in whitespace, which means we can go ahead
4199 // and end our current line.
4200 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4201 inlineMin = 0;
4202 shouldBreakLineAfterText = false;
4203 } else {
4204 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4205 inlineMin = endMin;
4206 shouldBreakLineAfterText = true;
4207 }
4208 }
4209
4210 if (hasBreak) {
4211 inlineMax += beginMax;
4212 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4213 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4214 inlineMax = endMax;
4215 addedTextIndent = true;
4216 } else
4217 inlineMax += std::max<float>(0, childMax);
4218 }
4219
4220 // Ignore spaces after a list marker.
4221 if (child->isListMarker())
4222 stripFrontSpaces = true;
4223 } else {
4224 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4225 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4226 inlineMin = inlineMax = 0;
4227 stripFrontSpaces = true;
4228 trailingSpaceChild = 0;
4229 addedTextIndent = true;
4230 }
4231
4232 if (!child->isText() && child->isRenderInline())
4233 isPrevChildInlineFlow = true;
4234 else
4235 isPrevChildInlineFlow = false;
4236
4237 oldAutoWrap = autoWrap;
4238 }
4239
4240 if (styleToUse.collapseWhiteSpace())
4241 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4242
4243 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4244 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4245}
4246
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004247}
4248// namespace WebCore