blob: 61fb0c701a76dcc4a544a17cc50c8eb8c805d5b5 [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)
bfulgham@apple.comb5953432015-02-13 21:56:01 +00005 * Copyright (C) 2003-2015 Apple Inc. All rights reserved.
hyatt@apple.com5388e672013-09-06 20:54:47 +00006 * 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"
cdumez@apple.coma92c4d62016-05-20 01:50:51 +000032#include "HTMLInputElement.h"
33#include "HTMLTextAreaElement.h"
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000034#include "HitTestLocation.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000035#include "InlineTextBox.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000036#include "LayoutRepainter.h"
simon.fraser@apple.com36676e52016-05-07 00:05:58 +000037#include "Logging.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000038#include "RenderCombineText.h"
hyatt@apple.com531e35d2017-04-13 16:37:00 +000039#include "RenderFlexibleBox.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000040#include "RenderInline.h"
akling@apple.comf3028052013-11-04 08:46:06 +000041#include "RenderIterator.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000042#include "RenderLayer.h"
zalan@apple.com8bf2a912015-04-10 03:15:50 +000043#include "RenderLineBreak.h"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000044#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000045#include "RenderMarquee.h"
hyatt@apple.com4e0bf862017-09-27 20:54:17 +000046#include "RenderMultiColumnFlow.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000047#include "RenderMultiColumnSet.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000048#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000049#include "RenderText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000050#include "RenderView.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000051#include "Settings.h"
antti@apple.com940f5872013-10-24 20:31:11 +000052#include "SimpleLineLayoutFunctions.h"
zalan@apple.com5cd09e52017-02-25 02:14:40 +000053#include "SimpleLineLayoutPagination.h"
antti@apple.com4918b4d2017-08-14 13:20:47 +000054#include "TextAutoSizing.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000055#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000056#include "VisiblePosition.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000057
hyatt@apple.com5388e672013-09-06 20:54:47 +000058namespace WebCore {
59
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000060bool RenderBlock::s_canPropagateFloatIntoSibling = false;
61
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000062struct SameSizeAsMarginInfo {
63 uint32_t bitfields : 16;
64 LayoutUnit margins[2];
65};
66
67COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000068COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000069
70// Our MarginInfo state used when laying out block children.
hyatt@apple.com9a79c622015-09-15 18:38:18 +000071RenderBlockFlow::MarginInfo::MarginInfo(const RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000072 : m_atBeforeSideOfBlock(true)
73 , m_atAfterSideOfBlock(false)
74 , m_hasMarginBeforeQuirk(false)
75 , m_hasMarginAfterQuirk(false)
76 , m_determinedMarginBeforeQuirk(false)
77 , m_discardMargin(false)
78{
akling@apple.com827be9c2013-10-29 02:58:43 +000079 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000080 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000081 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000082
akling@apple.com827be9c2013-10-29 02:58:43 +000083 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000084
85 // If any height other than auto is specified in CSS, then we don't collapse our bottom
86 // margins with our children's margins. To do otherwise would be to risk odd visual
87 // effects when the children overflow out of the parent block and yet still collapse
88 // with it. We also don't collapse if we have any bottom border/padding.
89 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000090 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000091
weinig@apple.com12840dc2013-10-22 23:59:08 +000092 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000093
weinig@apple.com12840dc2013-10-22 23:59:08 +000094 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000095
weinig@apple.com12840dc2013-10-22 23:59:08 +000096 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
97 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000098}
99
antti@apple.com454418f2016-04-25 19:49:23 +0000100RenderBlockFlow::RenderBlockFlow(Element& element, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000101 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
dbates@webkit.org102013c2016-09-26 21:51:25 +0000102#if ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +0000103 , m_widthForTextAutosizing(-1)
104 , m_lineCountForTextAutosizing(NOT_SET)
105#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000106{
weinig@apple.com611b9292013-10-20 22:57:54 +0000107 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000108}
109
antti@apple.com454418f2016-04-25 19:49:23 +0000110RenderBlockFlow::RenderBlockFlow(Document& document, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000111 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
dbates@webkit.org102013c2016-09-26 21:51:25 +0000112#if ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +0000113 , m_widthForTextAutosizing(-1)
114 , m_lineCountForTextAutosizing(NOT_SET)
115#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000116{
weinig@apple.com611b9292013-10-20 22:57:54 +0000117 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000118}
119
120RenderBlockFlow::~RenderBlockFlow()
121{
simon.fraser@apple.com9812a452017-03-20 17:28:55 +0000122 // Do not add any code here. Add it to willBeDestroyed() instead.
hyatt@apple.com5388e672013-09-06 20:54:47 +0000123}
124
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000125void RenderBlockFlow::insertedIntoTree()
126{
127 RenderBlock::insertedIntoTree();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000128}
129
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000130void RenderBlockFlow::willBeDestroyed()
131{
weinig@apple.com611b9292013-10-20 22:57:54 +0000132 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
133 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
134 destroyLeftoverChildren();
135
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +0000136 if (!renderTreeBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000137 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000138 // We can't wait for RenderBox::destroy to clear the selection,
139 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000140 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000141 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000142
143 // If we are an anonymous block, then our line boxes might have children
144 // that will outlast this block. In the non-anonymous block case those
145 // children will be destroyed by the time we return from this function.
146 if (isAnonymousBlock()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +0000147 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000148 while (auto childBox = box->firstChild())
149 childBox->removeFromParent();
150 }
151 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000152 } else if (parent())
153 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000154 }
155
akling@apple.com31dd4f42013-10-30 22:27:59 +0000156 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000157
simon.fraser@apple.com9812a452017-03-20 17:28:55 +0000158 blockWillBeDestroyed();
weinig@apple.com611b9292013-10-20 22:57:54 +0000159
160 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
161 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000162}
163
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000164RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
165{
166 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
167 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
168 // to avoid floats.
169 parentHasFloats = false;
170 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
171 if (is<RenderBlockFlow>(*sibling)) {
172 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
173 if (!siblingBlock.avoidsFloats())
174 return &siblingBlock;
175 }
176 if (sibling->isFloating())
177 parentHasFloats = true;
178 }
179 return nullptr;
180}
181
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000182void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000183{
184 if (m_floatingObjects)
185 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
186
187 HashSet<RenderBox*> oldIntrudingFloatSet;
188 if (!childrenInline() && m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000189 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
190 auto end = floatingObjectSet.end();
191 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
192 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000193 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000194 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000195 }
196 }
197
198 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000199 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000200 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000201 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000202 if (!oldIntrudingFloatSet.isEmpty())
203 markAllDescendantsWithFloatsForLayout();
204 return;
205 }
206
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000207 RendererToFloatInfoMap floatMap;
208
209 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000210 if (childrenInline())
211 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
212 else
213 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000214 }
215
216 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
217 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
218 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
antti@apple.comae85e112017-08-31 23:27:02 +0000219 if (!is<RenderBlockFlow>(parent()))
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000220 return;
221
robert@webkit.org97037ef2013-11-20 19:26:10 +0000222 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
223 // them (as opposed to floats they contain themselves) so check for those here too.
antti@apple.comae85e112017-08-31 23:27:02 +0000224 auto& parentBlock = downcast<RenderBlockFlow>(*parent());
225 bool parentHasFloats = false;
226 RenderBlockFlow* previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000227 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000228 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000229 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000230
231 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000232 if (previousBlock)
233 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000234 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000235 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000236 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000237 }
238
239 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000240 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000241 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000242
243 if (childrenInline()) {
244 LayoutUnit changeLogicalTop = LayoutUnit::max();
245 LayoutUnit changeLogicalBottom = LayoutUnit::min();
246 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000247 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
248 auto end = floatingObjectSet.end();
249 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000250 const auto& floatingObject = *it->get();
251 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000252 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000253 if (oldFloatingObject) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000254 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
255 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000256 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000257 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000258 } else {
259 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000260 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
261 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000262 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000263 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000264 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000265 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000266 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
267 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000268 }
269 }
270
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000271 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
272 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
273 oldFloatingObject->originatingLine()->markDirty();
274 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000275 } else {
276 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000277 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000278 }
279 }
280 }
281
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000282 auto end = floatMap.end();
283 for (auto it = floatMap.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000284 const auto& floatingObject = *it->value.get();
285 if (!floatingObject.isDescendant()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000286 changeLogicalTop = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000287 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000288 }
289 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000290
291 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
292 } else if (!oldIntrudingFloatSet.isEmpty()) {
293 // If there are previously intruding floats that no longer intrude, then children with floats
294 // should also get layout because they might need their floating object lists cleared.
295 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
296 markAllDescendantsWithFloatsForLayout();
297 else {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000298 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
299 auto end = floatingObjectSet.end();
300 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
301 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000302 if (!oldIntrudingFloatSet.isEmpty())
303 markAllDescendantsWithFloatsForLayout();
304 }
305 }
306}
307
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000308void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
309{
310 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
311 // The min/max intrinsic widths calculated really tell how much space elements need when
312 // laid out inside the columns. In order to eventually end up with the desired column width,
313 // we need to convert them to values pertaining to the multicol container.
314 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
315 LayoutUnit columnWidth;
316 LayoutUnit colGap = columnGap();
317 LayoutUnit gapExtra = (columnCount - 1) * colGap;
318 if (style().hasAutoColumnWidth())
319 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
320 else {
321 columnWidth = style().columnWidth();
322 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
323 }
324 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
325 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
326 // performing a layout pass, but this is not an appropriate time or place for layout. The
327 // good news is that if height is unconstrained and there are no explicit breaks, the
328 // resolved column-count really should be 1.
329 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
330 }
331}
332
333void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
334{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000335 if (childrenInline())
336 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
337 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000338 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
339
340 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
341
342 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
343
344 if (!style().autoWrap() && childrenInline()) {
345 // A horizontal marquee with inline children has no minimum width.
346 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
347 minLogicalWidth = 0;
348 }
349
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000350 if (is<RenderTableCell>(*this)) {
351 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000352 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
353 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
354 }
355
rego@igalia.com76760c72015-05-14 16:37:27 +0000356 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000357 maxLogicalWidth += scrollbarWidth;
358 minLogicalWidth += scrollbarWidth;
359}
360
361bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
362{
363 bool changed = recomputeLogicalWidth();
364
365 LayoutUnit oldColumnWidth = computedColumnWidth();
366 computeColumnCountAndWidth();
367
368 return changed || oldColumnWidth != computedColumnWidth();
369}
370
371LayoutUnit RenderBlockFlow::columnGap() const
372{
373 if (style().hasNormalColumnGap())
374 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
375 return style().columnGap();
376}
377
378void RenderBlockFlow::computeColumnCountAndWidth()
zalan@apple.com748d3822016-12-02 21:25:15 +0000379{
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000380 // Calculate our column width and column count.
381 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
382 unsigned desiredColumnCount = 1;
383 LayoutUnit desiredColumnWidth = contentLogicalWidth();
zalan@apple.com08aaba72016-12-02 23:05:48 +0000384
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000385 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
386 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
387 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
388 return;
389 }
zalan@apple.com08aaba72016-12-02 23:05:48 +0000390
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000391 LayoutUnit availWidth = desiredColumnWidth;
392 LayoutUnit colGap = columnGap();
zalan@apple.com08aaba72016-12-02 23:05:48 +0000393 LayoutUnit colWidth = std::max<LayoutUnit>(1, style().columnWidth());
zalan@apple.com585798f2016-05-18 23:25:47 +0000394 unsigned colCount = std::max<unsigned>(1, style().columnCount());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000395
396 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
397 desiredColumnCount = colCount;
398 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
399 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
zalan@apple.com08aaba72016-12-02 23:05:48 +0000400 desiredColumnCount = std::max<unsigned>(1, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000401 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
402 } else {
zalan@apple.com08aaba72016-12-02 23:05:48 +0000403 desiredColumnCount = std::max<unsigned>(std::min(colCount, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned()), 1);
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000404 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
405 }
406 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
407}
408
zalan@apple.com809f4872016-12-08 18:20:01 +0000409bool RenderBlockFlow::willCreateColumns(std::optional<unsigned> desiredColumnCount) const
zalan@apple.com748d3822016-12-02 21:25:15 +0000410{
zalan@apple.com809f4872016-12-08 18:20:01 +0000411 // The following types are not supposed to create multicol context.
hyatt@apple.com80914862017-03-06 18:00:35 +0000412 if (isFileUploadControl() || isTextControl() || isListBox())
zalan@apple.com809f4872016-12-08 18:20:01 +0000413 return false;
commit-queue@webkit.org875cdb32017-10-02 17:59:36 +0000414 if (isRenderSVGBlock() || isRubyRun())
antti@apple.com411949d2017-08-30 17:28:10 +0000415 return false;
commit-queue@webkit.org875cdb32017-10-02 17:59:36 +0000416#if ENABLE(MATHML)
417 if (isRenderMathMLBlock())
418 return false;
419#endif // ENABLE(MATHML)
zalan@apple.com809f4872016-12-08 18:20:01 +0000420
zalan@apple.com748d3822016-12-02 21:25:15 +0000421 if (!firstChild())
422 return false;
423
antti@apple.com411949d2017-08-30 17:28:10 +0000424 if (style().styleType() != NOPSEUDO)
425 return false;
426
zalan@apple.com809f4872016-12-08 18:20:01 +0000427 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating in the RenderView instead.
428 if ((style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isDocumentElementRenderer() || isBody()))
429 return true;
430
zalan@apple.com748d3822016-12-02 21:25:15 +0000431 if (!style().specifiesColumns())
432 return false;
433
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000434 // column-axis with opposite writing direction initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000435 if (!style().hasInlineColumnAxis())
436 return true;
437
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000438 // Non-auto column-width always initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000439 if (!style().hasAutoColumnWidth())
440 return true;
441
zalan@apple.com809f4872016-12-08 18:20:01 +0000442 if (desiredColumnCount)
443 return desiredColumnCount.value() > 1;
444
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000445 // column-count > 1 always initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000446 if (!style().hasAutoColumnCount())
447 return style().columnCount() > 1;
448
449 ASSERT_NOT_REACHED();
450 return false;
451}
452
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000453void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
454{
455 ASSERT(needsLayout());
456
457 if (!relayoutChildren && simplifiedLayout())
458 return;
459
460 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
461
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000462 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000463 relayoutChildren = true;
464
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000465 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000466
467 LayoutUnit previousHeight = logicalHeight();
468 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
469 // for consistency with other render classes?
470 setLogicalHeight(0);
471
472 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000473 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000474
akling@apple.com827be9c2013-10-29 02:58:43 +0000475 const RenderStyle& styleToUse = style();
zalan@apple.comab6c9c32017-11-03 22:42:13 +0000476 LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000477
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000478 preparePaginationBeforeBlockLayout(relayoutChildren);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000479
480 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
481 // our current maximal positive and negative margins. These values are used when we
482 // are collapsed with adjacent blocks, so for example, if you have block A and B
483 // collapsing together, then you'd take the maximal positive margin from both A and B
484 // and subtract it from the maximal negative margin from both A and B to get the
485 // true collapsed margin. This algorithm is recursive, so when we finish layout()
486 // our block knows its current maximal positive/negative values.
487 //
488 // Start out by setting our margin values to our current margins. Table cells have
489 // no margins, so we don't fill in the values for table cells.
490 bool isCell = isTableCell();
491 if (!isCell) {
492 initMaxMarginValues();
493
akling@apple.com827be9c2013-10-29 02:58:43 +0000494 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
495 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000496 setPaginationStrut(0);
497 }
498
499 LayoutUnit repaintLogicalTop = 0;
500 LayoutUnit repaintLogicalBottom = 0;
501 LayoutUnit maxFloatLogicalBottom = 0;
502 if (!firstChild() && !isAnonymousBlock())
503 setChildrenInline(true);
504 if (childrenInline())
505 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
506 else
507 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
508
509 // Expand our intrinsic height to encompass floats.
510 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000511 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000512 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
513
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000514 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000515 ASSERT(!shouldBreakAtLineToAvoidWidow());
516 return;
517 }
518
519 // Calculate our new height.
520 LayoutUnit oldHeight = logicalHeight();
521 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
522
523 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000524 // This ensures the size information is correctly computed for the last auto-height fragment receiving content.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000525 if (is<RenderFragmentedFlow>(*this))
526 downcast<RenderFragmentedFlow>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000527
528 updateLogicalHeight();
529 LayoutUnit newHeight = logicalHeight();
530 if (oldHeight != newHeight) {
531 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
532 // 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 +0000533 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
534 if (blockFlow.isFloatingOrOutOfFlowPositioned())
535 continue;
536 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
537 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000538 }
539 }
540 }
541
542 bool heightChanged = (previousHeight != newHeight);
543 if (heightChanged)
544 relayoutChildren = true;
545
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000546 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000547
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000548 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
549 computeOverflow(oldClientAfterEdge);
550
551 statePusher.pop();
552
553 fitBorderToLinesIfNeeded();
554
zalan@apple.com4de96c52017-11-07 04:09:59 +0000555 if (view().frameView().layoutContext().layoutState()->m_pageLogicalHeight)
556 setPageLogicalOffset(view().frameView().layoutContext().layoutState()->pageLogicalOffset(this, logicalTop()));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000557
558 updateLayerTransform();
559
560 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
561 // we overflow or not.
562 updateScrollInfoAfterLayout();
563
564 // FIXME: This repaint logic should be moved into a separate helper function!
565 // Repaint with our new bounds if they are different from our old bounds.
566 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000567 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000568 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
569 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
570 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
571 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
572 if (hasOverflowClip()) {
573 // 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.
574 // 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.
575 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000576 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
577 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000578 }
579
580 LayoutRect repaintRect;
581 if (isHorizontalWritingMode())
582 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
583 else
584 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
585
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000586 if (hasOverflowClip()) {
587 // Adjust repaint rect for scroll offset
simon.fraser@apple.com24e03ba2016-05-11 04:48:08 +0000588 repaintRect.moveBy(-scrollPosition());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000589
590 // Don't allow this rect to spill out of our overflow box.
591 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
592 }
593
594 // Make sure the rect is still non-empty after intersecting for overflow above
595 if (!repaintRect.isEmpty()) {
596 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
597 if (hasReflection())
598 repaintRectangle(reflectedRect(repaintRect));
599 }
600 }
601
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000602 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000603}
604
605void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
606{
607 dirtyForLayoutFromPercentageHeightDescendants();
608
609 LayoutUnit beforeEdge = borderAndPaddingBefore();
610 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
611
612 setLogicalHeight(beforeEdge);
613
614 // Lay out our hypothetical grid line as though it occurs at the top of the block.
zalan@apple.com4de96c52017-11-07 04:09:59 +0000615 if (view().frameView().layoutContext().layoutState()->lineGrid() == this)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000616 layoutLineGridBox();
617
618 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000619 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000620
621 // Fieldsets need to find their legend and position it inside the border of the object.
622 // The legend then gets skipped during normal layout. The same is true for ruby text.
623 // It doesn't get included in the normal layout process but is instead skipped.
hyatt@apple.com80914862017-03-06 18:00:35 +0000624 layoutExcludedChildren(relayoutChildren);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000625
626 LayoutUnit previousFloatLogicalBottom = 0;
627 maxFloatLogicalBottom = 0;
628
629 RenderBox* next = firstChildBox();
630
631 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000632 RenderBox& child = *next;
633 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000634
hyatt@apple.com80914862017-03-06 18:00:35 +0000635 if (child.isExcludedFromNormalLayout())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000636 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
637
638 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
639
weinig@apple.com12840dc2013-10-22 23:59:08 +0000640 if (child.isOutOfFlowPositioned()) {
641 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000642 adjustPositionedBlock(child, marginInfo);
643 continue;
644 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000645 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000646 insertFloatingObject(child);
647 adjustFloatingBlock(marginInfo);
648 continue;
649 }
650
651 // Lay out the child.
652 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
653 }
654
655 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
656 // determining the correct collapsed bottom margin information.
657 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
658}
659
antti@apple.com940f5872013-10-24 20:31:11 +0000660void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
661{
akling@apple.coma12fee22015-02-01 02:58:13 +0000662 if (lineLayoutPath() == UndeterminedPath)
663 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000664
akling@apple.coma12fee22015-02-01 02:58:13 +0000665 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000666 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000667 return;
668 }
669
antti@apple.comfea51992013-10-28 13:39:23 +0000670 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000671 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
672}
673
weinig@apple.com12840dc2013-10-22 23:59:08 +0000674void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000675{
676 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
677 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
678
679 // The child is a normal flow object. Compute the margins we will use for collapsing now.
mmaxfield@apple.com09804f42016-03-23 00:58:34 +0000680 child.computeAndSetBlockDirectionMargins(*this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000681
682 // Try to guess our correct logical top position. In most cases this guess will
683 // be correct. Only if we're wrong (when we compute the real logical top position)
684 // will we have to potentially relayout.
685 LayoutUnit estimateWithoutPagination;
686 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
687
688 // 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 +0000689 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000690 LayoutUnit oldLogicalTop = logicalTopForChild(child);
691
692#if !ASSERT_DISABLED
zalan@apple.com4de96c52017-11-07 04:09:59 +0000693 LayoutSize oldLayoutDelta = view().frameView().layoutContext().layoutDelta();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000694#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000695 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000696 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000697 estimateFragmentRangeForBoxChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000698
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000699 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000700 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000701 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000702 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000703 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
704 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
705 // very large elements. If it does the comparison with oldLogicalTop might yield a
706 // false negative as adding and removing margins, borders etc from a saturated number
707 // might yield incorrect results. If this is the case always mark for layout.
708 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000709 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000710 // If an element might be affected by the presence of floats, then always mark it for
711 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000712 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000713 if (fb > logicalTopEstimate)
714 markDescendantsWithFloats = true;
715 }
716
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000717 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000718 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000719 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000720 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000721 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000722 }
723
hyatt@apple.comccad3742015-02-04 21:39:00 +0000724 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000725
weinig@apple.com12840dc2013-10-22 23:59:08 +0000726 bool childHadLayout = child.everHadLayout();
727 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000728 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000729 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000730
731 // Cache if we are at the top of the block right now.
732 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
733
734 // Now determine the correct ypos based off examination of collapsing margin
735 // values.
736 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
737
738 // Now check for clear.
739 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
740
zalan@apple.com4de96c52017-11-07 04:09:59 +0000741 bool paginated = view().frameView().layoutContext().layoutState()->isPaginated();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000742 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000743 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000744
745 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
746
747 // Now we have a final top position. See if it really does end up being different from our estimate.
748 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
749 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000750 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
751 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000752 // The child's width depends on the line width. When the child shifts to clear an item, its width can
753 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000754 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000755 }
756
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000757 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000758 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000759 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000760 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000761 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000762 }
763
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000764 if (updateFragmentRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000765 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000766
767 // In case our guess was wrong, relayout the child.
768 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000769
770 // We are no longer at the top of the block if we encounter a non-empty child.
771 // 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 +0000772 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000773 marginInfo.setAtBeforeSideOfBlock(false);
774
775 // Now place the child in the correct left position
776 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
777
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000778 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000779 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000780 if (mustSeparateMarginAfterForChild(child)) {
781 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
782 marginInfo.clearMargin();
783 }
784 // If the child has overhanging floats that intrude into following siblings (or possibly out
785 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000786 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000787 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000788
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000789 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000790 if (childOffset.width() || childOffset.height()) {
zalan@apple.com4de96c52017-11-07 04:09:59 +0000791 view().frameView().layoutContext().addLayoutDelta(childOffset);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000792
793 // If the child moved, we have to repaint it as well as any floating/positioned
794 // descendants. An exception is if we need a layout. In this case, we know we're going to
795 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000796 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
797 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000798 }
799
weinig@apple.com12840dc2013-10-22 23:59:08 +0000800 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
801 child.repaint();
802 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000803 }
804
805 if (paginated) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000806 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
807 fragmentedFlow->fragmentedFlowDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000808 // Check for an after page/column break.
809 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
810 if (newHeight != height())
811 setLogicalHeight(newHeight);
812 }
813
zalan@apple.com4de96c52017-11-07 04:09:59 +0000814 ASSERT(view().frameView().layoutContext().layoutDeltaMatches(oldLayoutDelta));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000815}
816
weinig@apple.com12840dc2013-10-22 23:59:08 +0000817void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000818{
819 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000820 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000821
822 LayoutUnit logicalTop = logicalHeight();
zalan@apple.com4d97a002016-02-24 17:13:33 +0000823 updateStaticInlinePositionForChild(child, logicalTop, DoNotIndentText);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000824
825 if (!marginInfo.canCollapseWithMarginBefore()) {
826 // Positioned blocks don't collapse margins, so add the margin provided by
827 // the container now. The child's own margin is added later when calculating its logical top.
828 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
829 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
830 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
831 }
832
weinig@apple.com12840dc2013-10-22 23:59:08 +0000833 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000834 if (childLayer->staticBlockPosition() != logicalTop) {
835 childLayer->setStaticBlockPosition(logicalTop);
836 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000837 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000838 }
839}
840
robert@webkit.org97037ef2013-11-20 19:26:10 +0000841LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
842{
843 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000844 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000845 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
846 return marginValuesForChild(*this).positiveMarginBefore();
847 return LayoutUnit();
848}
849
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000850void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
851{
852 LayoutUnit startPosition = borderStart() + paddingStart();
mmaxfield@apple.com4195a702016-04-27 01:25:26 +0000853 if (shouldPlaceBlockDirectionScrollbarOnLeft())
mmaxfield@apple.comaf573be2016-03-12 21:18:25 +0000854 startPosition += (style().isLeftToRightDirection() ? 1 : -1) * verticalScrollbarWidth();
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000855 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
856
857 // Add in our start margin.
858 LayoutUnit childMarginStart = marginStartForChild(child);
859 LayoutUnit newPosition = startPosition + childMarginStart;
860
861 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
862 // to shift over as necessary to dodge any floats that might get in the way.
antti@apple.comeae76122017-09-20 15:37:23 +0000863 if (child.avoidsFloats() && containsFloats())
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000864 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
865
866 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
867}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000868
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000869void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
870{
871 // The float should be positioned taking into account the bottom margin
872 // of the previous flow. We add that margin into the height, get the
873 // float positioned properly, and then subtract the margin out of the
874 // height again. In the case of self-collapsing blocks, we always just
875 // use the top margins, since the self-collapsing block collapsed its
876 // own bottom margin into its top margin.
877 //
878 // Note also that the previous flow may collapse its margin into the top of
879 // our block. If this is the case, then we do not add the margin in to our
880 // height when computing the position of the float. This condition can be tested
881 // for by simply calling canCollapseWithMarginBefore. See
882 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
883 // an example of this scenario.
884 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
885 setLogicalHeight(logicalHeight() + marginOffset);
886 positionNewFloats();
887 setLogicalHeight(logicalHeight() - marginOffset);
888}
889
zalan@apple.com4d97a002016-02-24 17:13:33 +0000890void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000891{
akling@apple.com827be9c2013-10-29 02:58:43 +0000892 if (child.style().isOriginalDisplayInlineType())
zalan@apple.com4d97a002016-02-24 17:13:33 +0000893 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, shouldIndentText));
weinig@apple.com12840dc2013-10-22 23:59:08 +0000894 else
895 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
896}
897
898void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
899{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000900 if (enclosingFragmentedFlow()) {
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000901 // Shift the inline position to exclude the fragment offset.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000902 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
903 }
904 child.layer()->setStaticInlinePosition(inlinePosition);
905}
906
907RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000908{
909 LayoutUnit childBeforePositive = 0;
910 LayoutUnit childBeforeNegative = 0;
911 LayoutUnit childAfterPositive = 0;
912 LayoutUnit childAfterNegative = 0;
913
914 LayoutUnit beforeMargin = 0;
915 LayoutUnit afterMargin = 0;
916
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000917 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000918
919 // If the child has the same directionality as we do, then we can just return its
920 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000921 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000922 if (childRenderBlock) {
923 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
924 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
925 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
926 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
927 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000928 beforeMargin = child.marginBefore();
929 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000930 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000931 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000932 // The child has a different directionality. If the child is parallel, then it's just
933 // flipped relative to us. We can use the margins for the opposite edges.
934 if (childRenderBlock) {
935 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
936 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
937 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
938 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
939 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000940 beforeMargin = child.marginAfter();
941 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000942 }
943 } else {
944 // The child is perpendicular to us, which means its margins don't collapse but are on the
945 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
946 beforeMargin = marginBeforeForChild(child);
947 afterMargin = marginAfterForChild(child);
948 }
949
950 // Resolve uncollapsing margins into their positive/negative buckets.
951 if (beforeMargin) {
952 if (beforeMargin > 0)
953 childBeforePositive = beforeMargin;
954 else
955 childBeforeNegative = -beforeMargin;
956 }
957 if (afterMargin) {
958 if (afterMargin > 0)
959 childAfterPositive = afterMargin;
960 else
961 childAfterNegative = -afterMargin;
962 }
963
964 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
965}
966
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000967bool RenderBlockFlow::childrenPreventSelfCollapsing() const
968{
969 if (!childrenInline())
970 return RenderBlock::childrenPreventSelfCollapsing();
971
antti@apple.comae85e112017-08-31 23:27:02 +0000972 return hasLines();
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000973}
974
weinig@apple.com12840dc2013-10-22 23:59:08 +0000975LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000976{
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000977 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
978}
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000979
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000980LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
981{
982 bool childDiscardMarginBefore = child ? mustDiscardMarginBeforeForChild(*child) : false;
983 bool childDiscardMarginAfter = child ? mustDiscardMarginAfterForChild(*child) : false;
984 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
985 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
986 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
987
rmorisset@apple.comab64b6c2017-10-09 16:49:13 +0000988 // The child discards the before margin when the after margin has discarded in the case of a self collapsing block.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000989 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000990
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000991 // Get the four margin values for the child and cache them.
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000992 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000993
994 // Get our max pos and neg top margins.
995 LayoutUnit posTop = childMargins.positiveMarginBefore();
996 LayoutUnit negTop = childMargins.negativeMarginBefore();
997
998 // For self-collapsing blocks, collapse our bottom margins into our
999 // top to get new posTop and negTop values.
1000 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +00001001 posTop = std::max(posTop, childMargins.positiveMarginAfter());
1002 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001003 }
1004
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001005 if (marginInfo.canCollapseWithMarginBefore()) {
1006 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1007 // This child is collapsing with the top of the
1008 // block. If it has larger margin values, then we need to update
1009 // our own maximal values.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001010 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +00001011 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001012
1013 // The minute any of the margins involved isn't a quirk, don't
1014 // collapse it away, even if the margin is smaller (www.webreference.com
1015 // has an example of this, a <dt> with 0.8em author-specified inside
1016 // a <dl> inside a <td>.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001017 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001018 setHasMarginBeforeQuirk(false);
1019 marginInfo.setDeterminedMarginBeforeQuirk(true);
1020 }
1021
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001022 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001023 // We have no top margin and our top child has a quirky margin.
1024 // We will pick up this quirky margin and pass it through.
1025 // This deals with the <td><div><p> case.
1026 // Don't do this for a block that split two inlines though. You do
1027 // still apply margins in this case.
1028 setHasMarginBeforeQuirk(true);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001029 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001030 } else
1031 // The before margin of the container will also discard all the margins it is collapsing with.
1032 setMustDiscardMarginBefore();
1033 }
1034
1035 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1036 if (childDiscardMarginBefore) {
1037 marginInfo.setDiscardMargin(true);
1038 marginInfo.clearMargin();
1039 }
1040
1041 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001042 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001043
1044 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1045 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001046
1047 LayoutUnit clearanceForSelfCollapsingBlock;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001048
robert@webkit.org97037ef2013-11-20 19:26:10 +00001049 // 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
1050 // 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
1051 // 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.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001052 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1053 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001054 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1055 }
1056
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001057 if (childIsSelfCollapsing) {
1058 // 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.
1059 // Also, the child's top position equals the logical height of the container.
1060 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1061 // This child has no height. We need to compute our
1062 // position before we collapse the child's margins together,
1063 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001064 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1065 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001066 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1067
1068 // Now collapse the child's margins together, which means examining our
1069 // bottom margin values as well.
1070 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1071 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1072
1073 if (!marginInfo.canCollapseWithMarginBefore())
1074 // We need to make sure that the position of the self-collapsing block
1075 // is correct, since it could have overflowing content
1076 // that needs to be positioned correctly (e.g., a block that
1077 // had a specified height of 0 but that actually had subcontent).
1078 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1079 }
1080 } else {
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001081 if (child && mustSeparateMarginBeforeForChild(*child)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001082 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1083 // If we are at the before side of the block and we collapse, ignore the computed margin
1084 // and just add the child margin to the container height. This will correctly position
1085 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001086 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001087 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(*child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001088 logicalTop = logicalHeight();
1089 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1090 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1091 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1092 // We're collapsing with a previous sibling's margins and not
1093 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001094 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001095 logicalTop = logicalHeight();
1096 }
1097
1098 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1099
1100 if (!marginInfo.discardMargin()) {
1101 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1102 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1103 } else
1104 marginInfo.clearMargin();
1105
1106 if (marginInfo.margin())
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001107 marginInfo.setHasMarginAfterQuirk(afterQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001108 }
1109
1110 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1111 // collapsed into the page edge.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001112 auto* layoutState = view().frameView().layoutContext().layoutState();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001113 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1114 && hasNextPage(beforeCollapseLogicalTop)) {
1115 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001116 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001117 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1118 }
1119
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001120 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001121 // 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
1122 // any floats from the parent will now overhang.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001123 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001124 LayoutUnit oldLogicalHeight = logicalHeight();
1125 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001126 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001127 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001128 setLogicalHeight(oldLogicalHeight);
1129
1130 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1131 // 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
1132 // floats in the parent that overhang |child|'s new logical top.
1133 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001134 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1135 child->setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001136 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001137
1138 return logicalTop;
1139}
1140
weinig@apple.com12840dc2013-10-22 23:59:08 +00001141LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001142{
1143 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1144 if (!heightIncrease)
1145 return yPos;
1146
weinig@apple.com12840dc2013-10-22 23:59:08 +00001147 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001148 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1149
1150 // For self-collapsing blocks that clear, they can still collapse their
1151 // margins with following siblings. Reset the current margins to represent
1152 // the self-collapsing block's margins only.
1153 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001154 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001155 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001156 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1157 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001158 } else
1159 marginInfo.clearMargin();
1160 marginInfo.setDiscardMargin(childDiscardMargin);
1161
1162 // CSS2.1 states:
1163 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1164 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1165 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1166 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1167 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001168 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001169 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1170 wouldCollapseMarginsWithParent = false;
1171 }
1172 if (wouldCollapseMarginsWithParent)
1173 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1174
robert@webkit.org97037ef2013-11-20 19:26:10 +00001175 // 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
1176 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1177 // 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
1178 // margins can collapse at the correct vertical position.
1179 // 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
1180 // (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],
1181 // i.e., clearance = [height of float] - margin-top".
1182 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001183 } else
1184 // Increase our height by the amount we had to clear.
1185 setLogicalHeight(logicalHeight() + heightIncrease);
1186
1187 if (marginInfo.canCollapseWithMarginBefore()) {
1188 // We can no longer collapse with the top of the block since a clear
1189 // occurred. The empty blocks collapse into the cleared block.
1190 // FIXME: This isn't quite correct. Need clarification for what to do
1191 // if the height the cleared block is offset by is smaller than the
1192 // margins involved.
1193 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1194 marginInfo.setAtBeforeSideOfBlock(false);
1195
1196 // 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 +00001197 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001198 }
1199
robert@webkit.org97037ef2013-11-20 19:26:10 +00001200 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001201}
1202
weinig@apple.com12840dc2013-10-22 23:59:08 +00001203void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001204{
1205 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1206 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1207 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001208 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001209 return;
1210
1211 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1212 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001213 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001214 positiveMarginBefore = 0;
1215 negativeMarginBefore = 0;
1216 discardMarginBefore = true;
1217 return;
1218 }
1219
1220 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001221 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1222 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001223
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001224 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001225 return;
1226
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001227 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001228 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001229 return;
1230
weinig@apple.com12840dc2013-10-22 23:59:08 +00001231 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001232 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1233 return;
1234
weinig@apple.com12840dc2013-10-22 23:59:08 +00001235 RenderBox* grandchildBox = childBlock.firstChildBox();
1236 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001237 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1238 break;
1239 }
1240
1241 // 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 +00001242 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001243 return;
1244
1245 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1246 if (grandchildBox->needsLayout()) {
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00001247 grandchildBox->computeAndSetBlockDirectionMargins(*this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001248 if (is<RenderBlock>(*grandchildBox)) {
1249 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1250 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1251 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001252 }
1253 }
1254
1255 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001256 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001257}
1258
weinig@apple.com12840dc2013-10-22 23:59:08 +00001259LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001260{
1261 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1262 // relayout if there are intruding floats.
1263 LayoutUnit logicalTopEstimate = logicalHeight();
1264 if (!marginInfo.canCollapseWithMarginBefore()) {
1265 LayoutUnit positiveMarginBefore = 0;
1266 LayoutUnit negativeMarginBefore = 0;
1267 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001268 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001269 // Try to do a basic estimation of how the collapse is going to go.
1270 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1271 } else {
1272 // Use the cached collapsed margin values from a previous layout. Most of the time they
1273 // will be right.
1274 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001275 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1276 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001277 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1278 }
1279
1280 // Collapse the result with our current margins.
1281 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001282 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001283 }
1284
1285 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1286 // page.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001287 auto* layoutState = view().frameView().layoutContext().layoutState();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001288 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1289 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001290 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001291
1292 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1293
1294 estimateWithoutPagination = logicalTopEstimate;
1295
1296 if (layoutState->isPaginated()) {
1297 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1298 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1299
1300 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1301 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1302
cdumez@apple.come9437792014-10-08 23:33:43 +00001303 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1304 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001305 }
1306
1307 return logicalTopEstimate;
1308}
1309
1310void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1311{
1312 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1313 // 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.
1314 // Don't update the max margin values because we won't need them anyway.
1315 if (marginInfo.discardMargin()) {
1316 setMustDiscardMarginAfter();
1317 return;
1318 }
1319
1320 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1321 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001322 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001323
1324 if (!marginInfo.hasMarginAfterQuirk())
1325 setHasMarginAfterQuirk(false);
1326
1327 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1328 // We have no bottom margin and our last child has a quirky margin.
1329 // We will pick up this quirky margin and pass it through.
1330 // This deals with the <td><div><p> case.
1331 setHasMarginAfterQuirk(true);
1332 }
1333}
1334
1335void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1336{
1337 marginInfo.setAtAfterSideOfBlock(true);
1338
robert@webkit.org97037ef2013-11-20 19:26:10 +00001339 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1340 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1341 // to perform now is at the child's margin-top - so adjust our height to that position.
1342 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001343 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1344 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001345
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001346 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001347 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1348 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1349 setLogicalHeight(logicalHeight() + marginInfo.margin());
1350
1351 // Now add in our bottom border/padding.
1352 setLogicalHeight(logicalHeight() + afterSide);
1353
1354 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1355 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001356 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001357
1358 // Update our bottom collapsed margin info.
1359 setCollapsedBottomMargin(marginInfo);
1360}
1361
1362void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1363{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001364 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001365 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001366 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001367 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001368 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001369
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001370 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1371 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001372}
1373
1374void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1375{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001376 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001377 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001378 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001379 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001380 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001381
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001382 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1383 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001384}
1385
1386void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1387{
akling@apple.com827be9c2013-10-29 02:58:43 +00001388 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001389 ASSERT(value);
1390 return;
1391 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001392
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001393 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001394 if (!value)
1395 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001396 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001397 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001398
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001399 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001400}
1401
1402void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1403{
akling@apple.com827be9c2013-10-29 02:58:43 +00001404 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001405 ASSERT(value);
1406 return;
1407 }
1408
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001409 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001410 if (!value)
1411 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001412 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001413 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001414
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001415 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001416}
1417
1418bool RenderBlockFlow::mustDiscardMarginBefore() const
1419{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001420 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001421}
1422
1423bool RenderBlockFlow::mustDiscardMarginAfter() const
1424{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001425 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001426}
1427
weinig@apple.com12840dc2013-10-22 23:59:08 +00001428bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001429{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001430 ASSERT(!child.selfNeedsLayout());
1431 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001432 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001433 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001434 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001435
1436 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1437 // In case the boxes are perpendicular we assume the property is not specified.
1438 return false;
1439}
1440
weinig@apple.com12840dc2013-10-22 23:59:08 +00001441bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001442{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001443 ASSERT(!child.selfNeedsLayout());
1444 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001445 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001446 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001447 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001448
1449 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1450 return false;
1451}
1452
weinig@apple.com12840dc2013-10-22 23:59:08 +00001453bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001454{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001455 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001456 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001457 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001458 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001459 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001460 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001461
1462 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1463 return false;
1464}
1465
weinig@apple.com12840dc2013-10-22 23:59:08 +00001466bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001467{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001468 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001469 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001470 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001471 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001472 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001473 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001474
1475 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1476 return false;
1477}
1478
weinig@apple.com12840dc2013-10-22 23:59:08 +00001479static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001480{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001481 RenderBlock* curr = child.containingBlock();
1482 while (curr && curr != &child.view()) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001483 if (curr->isRenderFragmentedFlow())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001484 return true;
1485 if (curr->isFloatingOrOutOfFlowPositioned())
1486 return false;
1487 curr = curr->containingBlock();
1488 }
1489 return true;
1490}
1491
weinig@apple.com12840dc2013-10-22 23:59:08 +00001492LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001493{
1494 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001495 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1496 bool isInsideMulticolFlow = fragmentedFlow;
1497 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
zalan@apple.com4de96c52017-11-07 04:09:59 +00001498 bool checkPageBreaks = !checkColumnBreaks && view().frameView().layoutContext().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001499 bool checkFragmentBreaks = false;
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001500 bool checkBeforeAlways = (checkColumnBreaks && child.style().breakBefore() == ColumnBreakBetween)
antti@apple.com52d83832017-09-20 12:58:45 +00001501 || (checkPageBreaks && alwaysPageBreak(child.style().breakBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001502 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001503 if (checkColumnBreaks) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001504 if (isInsideMulticolFlow)
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001505 checkFragmentBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001506 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001507 if (checkFragmentBreaks) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001508 LayoutUnit offsetBreakAdjustment = 0;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001509 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001510 return logicalOffset + offsetBreakAdjustment;
1511 }
1512 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1513 }
1514 return logicalOffset;
1515}
1516
weinig@apple.com12840dc2013-10-22 23:59:08 +00001517LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001518{
1519 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001520 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1521 bool isInsideMulticolFlow = fragmentedFlow;
1522 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
zalan@apple.com4de96c52017-11-07 04:09:59 +00001523 bool checkPageBreaks = !checkColumnBreaks && view().frameView().layoutContext().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001524 bool checkFragmentBreaks = false;
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001525 bool checkAfterAlways = (checkColumnBreaks && child.style().breakAfter() == ColumnBreakBetween)
antti@apple.com52d83832017-09-20 12:58:45 +00001526 || (checkPageBreaks && alwaysPageBreak(child.style().breakAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001527 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1528 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1529
1530 // So our margin doesn't participate in the next collapsing steps.
1531 marginInfo.clearMargin();
1532
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001533 if (checkColumnBreaks) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001534 if (isInsideMulticolFlow)
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001535 checkFragmentBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001536 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001537 if (checkFragmentBreaks) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001538 LayoutUnit offsetBreakAdjustment = 0;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001539 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001540 return logicalOffset + marginOffset + offsetBreakAdjustment;
1541 }
1542 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1543 }
1544 return logicalOffset;
1545}
1546
weinig@apple.com12840dc2013-10-22 23:59:08 +00001547LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001548{
cdumez@apple.come9437792014-10-08 23:33:43 +00001549 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001550
1551 if (estimateWithoutPagination != logicalTopAfterClear) {
1552 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1553 // position.
1554 setLogicalHeight(logicalTopAfterClear);
1555 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1556
weinig@apple.com12840dc2013-10-22 23:59:08 +00001557 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001558 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1559 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001560 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001561 }
1562
1563 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001564 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001565 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001566 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001567 }
1568
1569 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001570 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001571 }
1572
1573 LayoutUnit oldTop = logicalTopAfterClear;
1574
1575 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1576 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1577
1578 if (pageLogicalHeightForOffset(result)) {
1579 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001580 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001581 if (spaceShortage > 0) {
1582 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1583 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1584 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1585 // This should be improved, though, because here we just pretend that the child is
1586 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1587 // where there's no child content, border or padding. In other words, we risk stretching more
1588 // than necessary.
1589 setPageBreak(result, spaceShortage);
1590 }
1591 }
1592
1593 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1594 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1595 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1596
1597 LayoutUnit paginationStrut = 0;
1598 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1599 if (unsplittableAdjustmentDelta)
1600 paginationStrut = unsplittableAdjustmentDelta;
1601 else if (childRenderBlock && childRenderBlock->paginationStrut())
1602 paginationStrut = childRenderBlock->paginationStrut();
1603
1604 if (paginationStrut) {
1605 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1606 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1607 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1608 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1609 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1610 // and pushes to the next page anyway, so not too concerned about it.
1611 setPaginationStrut(result + paginationStrut);
1612 if (childRenderBlock)
1613 childRenderBlock->setPaginationStrut(0);
1614 } else
1615 result += paginationStrut;
1616 }
1617
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001618 // Similar to how we apply clearance. Boost height() to be the place where we're going to position the child.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001619 setLogicalHeight(logicalHeight() + (result - oldTop));
1620
1621 // Return the final adjusted logical top.
1622 return result;
1623}
1624
antti@apple.com5c4302b2016-04-26 18:20:09 +00001625static inline LayoutUnit calculateMinimumPageHeight(const RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001626{
1627 // We may require a certain minimum number of lines per page in order to satisfy
1628 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001629 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001630 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001631 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001632 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1633 line = line->prevRootBox();
1634
1635 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1636 // adjustLinePositionForPagination() for more details.
1637 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001638 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001639 }
1640 return lineBottom - lineTop;
1641}
1642
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001643static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1644{
zalan@apple.coma1cff3a2017-01-14 18:45:20 +00001645 auto& renderer = lineBox.renderer();
bfulgham@apple.com62729772015-04-29 02:26:07 +00001646
zalan@apple.coma1cff3a2017-01-14 18:45:20 +00001647 if (!renderer.settings().appleMailPaginationQuirkEnabled())
bfulgham@apple.com62729772015-04-29 02:26:07 +00001648 return false;
1649
cdumez@apple.combee81ac2016-04-21 23:28:48 +00001650 if (renderer.element() && renderer.element()->idForStyleResolution() == "messageContentContainer")
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001651 return true;
1652
1653 return false;
1654}
zalan@apple.come031dfb2016-08-25 18:41:22 +00001655
1656static void clearShouldBreakAtLineToAvoidWidowIfNeeded(RenderBlockFlow& blockFlow)
1657{
1658 if (!blockFlow.shouldBreakAtLineToAvoidWidow())
1659 return;
1660 blockFlow.clearShouldBreakAtLineToAvoidWidow();
1661 blockFlow.setDidBreakAtLineToAvoidWidow();
1662}
1663
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001664void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsFragment, RenderFragmentedFlow* fragmentedFlow)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001665{
1666 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1667 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1668 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1669 // of the first column.
1670 //
1671 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1672 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1673 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1674 // for overflow to occur), and then cache visible overflow for each column rect.
1675 //
1676 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1677 // content that paints in a previous column (and content that paints in the following column).
1678 //
1679 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1680 // at least make positive leading work in typical cases.
1681 //
1682 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1683 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1684 // line and all following lines.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001685 overflowsFragment = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001686 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001687 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1688 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001689 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001690 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001691 logicalOffset += delta;
1692 lineBox->setPaginationStrut(0);
1693 lineBox->setIsFirstAfterPageBreak(false);
1694 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001695 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001696 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1697 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001698 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001699 // 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.
1700 // 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 +00001701 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001702 }
1703
1704 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1705 // 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
1706 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1707 // 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
1708 // top of the page.
1709 // 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
1710 // this will be a real-world issue. For now we don't try to deal with this problem.
1711 logicalOffset = intMaxForLayoutUnit;
1712 logicalBottom = intMinForLayoutUnit;
1713 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1714 lineHeight = logicalBottom - logicalOffset;
zalan@apple.come031dfb2016-08-25 18:41:22 +00001715 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) {
1716 // Give up. We're genuinely too big even after excluding blank space and overflow.
1717 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
1718 return;
1719 }
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001720 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1721 }
1722
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001723 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001724 overflowsFragment = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001725
1726 int lineIndex = lineCount(lineBox);
1727 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
zalan@apple.come031dfb2016-08-25 18:41:22 +00001728 if (lineBreakToAvoidWidow() == lineIndex)
1729 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001730 // If we have a non-uniform page height, then we have to shift further possibly.
1731 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1732 return;
1733 if (lineHeight > pageLogicalHeight) {
1734 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001735 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001736 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001737 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001738 overflowsFragment = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001739 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001740 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1741 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001742 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001743 && !isOutOfFlowPositioned() && !isTableCell()) {
1744 auto firstRootBox = this->firstRootBox();
1745 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1746 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001747 if (needsAppleMailPaginationQuirk(*lineBox))
1748 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001749 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1750 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001751 delta += remainingLogicalHeight;
1752 lineBox->setPaginationStrut(remainingLogicalHeight);
1753 lineBox->setIsFirstAfterPageBreak(true);
1754 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001755 } else if (remainingLogicalHeight == pageLogicalHeight) {
1756 // We're at the very top of a page or column.
1757 if (lineBox != firstRootBox())
1758 lineBox->setIsFirstAfterPageBreak(true);
1759 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1760 setPageBreak(logicalOffset, lineHeight);
1761 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001762}
1763
1764void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1765{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001766 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001767 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1768 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001769}
1770
abucur@adobe.comfc497132013-10-04 08:49:21 +00001771void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1772{
1773 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001774 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001775 return;
1776
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001777 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001778}
1779
1780void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1781{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001782 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001783 return;
1784
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001785 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001786}
1787
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001788void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1789{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001790 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001791 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001792 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001793
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001794 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001795}
1796
1797bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1798{
1799 if (!shouldBreakAtLineToAvoidWidow())
1800 return false;
1801
1802 statePusher.pop();
1803 setEverHadLayout(true);
1804 layoutBlock(false);
1805 return true;
1806}
1807
weinig@apple.com31324fd2013-10-28 19:22:51 +00001808bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1809{
zalan@apple.com4de96c52017-11-07 04:09:59 +00001810 ASSERT(view().frameView().layoutContext().layoutState() && view().frameView().layoutContext().layoutState()->isPaginated());
weinig@apple.com31324fd2013-10-28 19:22:51 +00001811
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001812 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1813 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001814 return true; // Printing and multi-column both make new pages to accommodate content.
1815
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001816 // See if we're in the last fragment.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001817 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001818 RenderFragmentContainer* fragment = fragmentedFlow->fragmentAtBlockOffset(this, pageOffset, true);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001819 if (!fragment)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001820 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001821
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001822 if (fragment->isLastFragment())
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001823 return fragment->isRenderFragmentContainerSet() || (pageBoundaryRule == IncludePageBoundary && pageOffset == fragment->logicalTopForFragmentedFlowContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001824
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001825 RenderFragmentContainer* startFragment = nullptr;
1826 RenderFragmentContainer* endFragment = nullptr;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001827 fragmentedFlow->getFragmentRangeForBox(this, startFragment, endFragment);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001828 return (endFragment && fragment != endFragment);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001829}
1830
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001831LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, LayoutUnit childBeforeMargin, LayoutUnit childAfterMargin)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001832{
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001833 // When flexboxes are embedded inside a block flow, they don't perform any adjustments for unsplittable
1834 // children. We'll treat flexboxes themselves as unsplittable just to get them to paginate properly inside
1835 // a block flow.
1836 bool isUnsplittable = childBoxIsUnsplittableForFragmentation(child);
1837 if (!isUnsplittable && !(child.isFlexibleBox() && !downcast<RenderFlexibleBox>(child).isFlexibleBoxImpl()))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001838 return logicalOffset;
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001839
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001840 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001841 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + childBeforeMargin + childAfterMargin;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001842 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001843 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001844 if (isUnsplittable)
1845 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001846 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1847 || !hasNextPage(logicalOffset))
1848 return logicalOffset;
1849 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1850 if (remainingLogicalHeight < childLogicalHeight) {
1851 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1852 return logicalOffset;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001853 auto result = logicalOffset + remainingLogicalHeight;
1854 bool isInitialLetter = child.isFloating() && child.style().styleType() == FIRST_LETTER && child.style().initialLetterDrop() > 0;
1855 if (isInitialLetter) {
1856 // Increase our logical height to ensure that lines all get pushed along with the letter.
1857 setLogicalHeight(logicalOffset + remainingLogicalHeight);
1858 }
1859 return result;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001860 }
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001861
weinig@apple.com31324fd2013-10-28 19:22:51 +00001862 return logicalOffset;
1863}
1864
1865bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1866{
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001867 bool checkFragment = false;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001868 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1869 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1870 if (minimumLogicalHeight <= pageLogicalHeight)
1871 return true;
1872 if (!hasNextPage(logicalOffset + adjustment))
1873 return false;
1874 adjustment += pageLogicalHeight;
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001875 checkFragment = true;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001876 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001877 return !checkFragment;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001878}
1879
1880void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1881{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001882 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1883 fragmentedFlow->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001884}
1885
1886void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1887{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001888 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1889 fragmentedFlow->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001890}
1891
1892LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1893{
1894 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1895 if (!pageLogicalHeight)
1896 return logicalOffset;
1897
1898 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1899 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1900 if (pageBoundaryRule == ExcludePageBoundary)
1901 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1902 return logicalOffset + remainingLogicalHeight;
1903}
1904
1905LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1906{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001907 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1908 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001909 auto* layoutState = view().frameView().layoutContext().layoutState();
1910 LayoutUnit pageLogicalHeight = layoutState->m_pageLogicalHeight;
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001911 if (!pageLogicalHeight)
1912 return 0;
1913
zalan@apple.com4de96c52017-11-07 04:09:59 +00001914 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? layoutState->m_pageOffset.height() : layoutState->m_pageOffset.width();
1915 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? layoutState->m_layoutOffset.height() : layoutState->m_layoutOffset.width();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001916
1917 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001918 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1919 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001920 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001921 return firstPageLogicalTop + fragmentedFlow->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001922}
1923
1924LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1925{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001926 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1927 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001928 LayoutUnit pageLogicalHeight = view().frameView().layoutContext().layoutState()->m_pageLogicalHeight;
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001929 if (!pageLogicalHeight)
1930 return 0;
1931
1932 // Now check for a flow thread.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001933 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1934 if (!fragmentedFlow)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001935 return pageLogicalHeight;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001936 return fragmentedFlow->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
weinig@apple.com31324fd2013-10-28 19:22:51 +00001937}
1938
1939LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1940{
1941 offset += offsetFromLogicalTopOfFirstPage();
1942
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001943 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1944 if (!fragmentedFlow) {
zalan@apple.com4de96c52017-11-07 04:09:59 +00001945 LayoutUnit pageLogicalHeight = view().frameView().layoutContext().layoutState()->m_pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001946 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1947 if (pageBoundaryRule == IncludePageBoundary) {
1948 // If includeBoundaryPoint is true the line exactly on the top edge of a
1949 // column will act as being part of the previous column.
1950 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1951 }
1952 return remainingHeight;
1953 }
1954
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001955 return fragmentedFlow->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001956}
1957
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001958LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1959{
antti@apple.comeae76122017-09-20 15:37:23 +00001960 return logicalHeightForChild(child);
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001961}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001962
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001963void RenderBlockFlow::layoutLineGridBox()
1964{
akling@apple.com827be9c2013-10-29 02:58:43 +00001965 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001966 setLineGridBox(0);
1967 return;
1968 }
1969
1970 setLineGridBox(0);
1971
akling@apple.com1aa97b02013-10-31 21:59:49 +00001972 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001973 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1974 lineGridBox->setConstructed();
1975 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1976 VerticalPositionCache verticalPositionCache;
1977 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1978
aestes@apple.com13aae082016-01-02 08:03:08 +00001979 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001980
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001981 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1982 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1983 // to this grid.
1984}
1985
weinig@apple.com12840dc2013-10-22 23:59:08 +00001986bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001987{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001988 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001989}
1990
1991void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1992{
1993 RenderBlock::styleDidChange(diff, oldStyle);
1994
1995 // After our style changed, if we lose our ability to propagate floats into next sibling
1996 // blocks, then we need to find the top most parent containing that overhanging float and
1997 // then mark its descendants with floats for layout and clear all floats from its next
1998 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1999 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
2000 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2001 RenderBlockFlow* parentBlock = this;
2002 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002003
weinig@apple.comc77041e2013-12-14 18:05:45 +00002004 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2005 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00002006 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00002007 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002008 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2009 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002010 if (ancestor.hasOverhangingFloat(renderer)) {
2011 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002012 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002013 }
2014 }
2015 }
2016 }
2017
2018 parentBlock->markAllDescendantsWithFloatsForLayout();
2019 parentBlock->markSiblingsWithFloatsForLayout();
2020 }
zalan@apple.com07a1ebc2017-03-16 01:56:57 +00002021 // Fresh floats need to be reparented if they actually belong to the previous anonymous block.
2022 // It copies the logic of RenderBlock::addChildIgnoringContinuation
2023 if (noLongerAffectsParentBlock() && style().isFloating() && previousSibling() && previousSibling()->isAnonymousBlock())
2024 downcast<RenderBoxModelObject>(*parent()).moveChildTo(&downcast<RenderBoxModelObject>(*previousSibling()), this);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002025
antti@apple.com9e891c82014-05-22 06:12:34 +00002026 if (diff >= StyleDifferenceRepaint) {
2027 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2028 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2029 invalidateLineLayoutPath();
2030 }
2031
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002032 if (multiColumnFlow())
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002033 updateStylesForColumnChildren();
2034}
2035
2036void RenderBlockFlow::updateStylesForColumnChildren()
2037{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002038 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFragmentedFlow() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
antti@apple.com454418f2016-04-25 19:49:23 +00002039 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002040}
2041
akling@apple.combdae43242013-10-25 12:00:20 +00002042void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002043{
akling@apple.com827be9c2013-10-29 02:58:43 +00002044 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002045 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2046
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002047 if (oldStyle) {
2048 EPosition oldPosition = oldStyle->position();
2049 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002050
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002051 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2052 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2053 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002054 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002055 }
2056
2057 RenderBlock::styleWillChange(diff, newStyle);
2058}
2059
antti@apple.coma2c7f242013-10-22 22:37:25 +00002060void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002061{
2062 if (containsFloats())
2063 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002064
antti@apple.comfea51992013-10-28 13:39:23 +00002065 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002066 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002067 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002068 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002069 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002070
antti@apple.coma2c7f242013-10-22 22:37:25 +00002071 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002072}
2073
zalan@apple.com232b0932016-12-24 18:00:00 +00002074void RenderBlockFlow::addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002075{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002076 // When a portion of the render tree is being detached, anonymous blocks
2077 // will be combined as their children are deleted. In this process, the
2078 // anonymous block later in the tree is merged into the one preceeding it.
2079 // It can happen that the later block (this) contains floats that the
2080 // previous block (toBlockFlow) did not contain, and thus are not in the
2081 // floating objects list for toBlockFlow. This can result in toBlockFlow
2082 // containing floats that are not in it's floating objects list, but are in
2083 // the floating objects lists of siblings and parents. This can cause
2084 // problems when the float itself is deleted, since the deletion code
2085 // assumes that if a float is not in it's containing block's floating
2086 // objects list, it isn't in any floating objects list. In order to
2087 // preserve this condition (removing it has serious performance
2088 // implications), we need to copy the floating objects from the old block
2089 // (this) to the new block (toBlockFlow). The float's metrics will likely
2090 // all be wrong, but since toBlockFlow is already marked for layout, this
2091 // will get fixed before anything gets displayed.
2092 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
zalan@apple.com232b0932016-12-24 18:00:00 +00002093 if (!m_floatingObjects)
2094 return;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002095
zalan@apple.com232b0932016-12-24 18:00:00 +00002096 if (!toBlockFlow.m_floatingObjects)
2097 toBlockFlow.createFloatingObjects();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002098
zalan@apple.com26018542017-03-30 01:25:00 +00002099 for (auto& floatingObject : m_floatingObjects->set()) {
2100 if (toBlockFlow.containsFloat(floatingObject->renderer()))
2101 continue;
zalan@apple.com232b0932016-12-24 18:00:00 +00002102 toBlockFlow.m_floatingObjects->add(floatingObject->cloneForNewParent());
zalan@apple.com26018542017-03-30 01:25:00 +00002103 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002104}
2105
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002106void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002107{
zalan@apple.com232b0932016-12-24 18:00:00 +00002108 auto& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002109 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
zalan@apple.com232b0932016-12-24 18:00:00 +00002110 addFloatsToNewParent(toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002111}
2112
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002113void RenderBlockFlow::addOverflowFromFloats()
2114{
2115 if (!m_floatingObjects)
2116 return;
2117
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002118 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2119 auto end = floatingObjectSet.end();
2120 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002121 const auto& floatingObject = *it->get();
2122 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002123 addOverflowFromChild(&floatingObject.renderer(), floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002124 }
2125}
2126
2127void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2128{
2129 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2130
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002131 if (!multiColumnFlow() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002132 addOverflowFromFloats();
2133}
2134
2135void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2136{
2137 // Repaint any overhanging floats (if we know we're the one to paint them).
2138 // Otherwise, bail out.
2139 if (!hasOverhangingFloats())
2140 return;
2141
2142 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2143 // in this block. Better yet would be to push extra state for the containers of other floats.
zalan@apple.com4de96c52017-11-07 04:09:59 +00002144 LayoutStateDisabler layoutStateDisabler(view().frameView().layoutContext());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002145 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2146 auto end = floatingObjectSet.end();
2147 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002148 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002149 // Only repaint the object if it is overhanging, is not in its own layer, and
2150 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2151 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002152 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002153 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002154 && !renderer.hasSelfPaintingLayer()
2155 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2156 renderer.repaint();
2157 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002158 }
2159 }
2160}
2161
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002162void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002163{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002164 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002165
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002166 if (!multiColumnFlow() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002167 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002168
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002169 // Iterate over our children and paint the column rules as needed.
2170 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2171 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2172 columnSet.paintColumnRules(paintInfo, childPoint);
2173 }
2174}
2175
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002176void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2177{
2178 if (!m_floatingObjects)
2179 return;
2180
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002181 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2182 auto end = floatingObjectSet.end();
2183 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002184 const auto& floatingObject = *it->get();
2185 auto& renderer = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002186 // Only paint the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002187 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002188 PaintInfo currentPaintInfo(paintInfo);
2189 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002190 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, paintOffset + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002191 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002192 if (!preservePhase) {
2193 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002194 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002195 currentPaintInfo.phase = PaintPhaseFloat;
zalan@apple.com6816b132015-10-17 19:14:53 +00002196 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002197 currentPaintInfo.phase = PaintPhaseForeground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002198 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002199 currentPaintInfo.phase = PaintPhaseOutline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002200 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002201 }
2202 }
2203 }
2204}
2205
weinig@apple.com12840dc2013-10-22 23:59:08 +00002206void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002207{
2208 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002209 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2210 auto end = floatingObjectSet.end();
2211 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002212 const auto& floatingObject = *it->get();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002213 LayoutRect floatBox(offsetFromRootBlock.width(), offsetFromRootBlock.height(), floatingObject.renderer().width(), floatingObject.renderer().height());
2214 floatBox.move(floatingObject.locationOffsetOfBorderBox());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002215 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002216 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002217 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002218 }
2219 }
2220}
2221
2222void RenderBlockFlow::createFloatingObjects()
2223{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002224 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002225}
2226
2227void RenderBlockFlow::removeFloatingObjects()
2228{
2229 if (!m_floatingObjects)
2230 return;
2231
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002232 markSiblingsWithFloatsForLayout();
2233
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002234 m_floatingObjects->clear();
2235}
2236
weinig@apple.com12840dc2013-10-22 23:59:08 +00002237FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002238{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002239 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002240
2241 // Create the list of special objects if we don't aleady have one
2242 if (!m_floatingObjects)
2243 createFloatingObjects();
2244 else {
2245 // Don't insert the floatingObject again if it's already in the list
2246 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002247 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002248 if (it != floatingObjectSet.end())
2249 return it->get();
2250 }
2251
2252 // Create the special floatingObject entry & append it to the list
2253
weinig@apple.com12840dc2013-10-22 23:59:08 +00002254 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002255
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002256 // Our location is irrelevant if we're unsplittable or no pagination is in effect. Just lay out the float.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002257 bool isChildRenderBlock = floatBox.isRenderBlock();
zalan@apple.com4de96c52017-11-07 04:09:59 +00002258 if (isChildRenderBlock && !floatBox.needsLayout() && view().frameView().layoutContext().layoutState()->pageLogicalHeightChanged())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002259 floatBox.setChildNeedsLayout(MarkOnlyThis);
zalan@apple.com4de96c52017-11-07 04:09:59 +00002260
2261 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().frameView().layoutContext().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002262 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2263 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002264 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002265 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2266 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002267 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002268 floatBox.updateLogicalWidth();
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00002269 floatBox.computeAndSetBlockDirectionMargins(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002270 }
2271
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002272 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002273
aestes@apple.com13aae082016-01-02 08:03:08 +00002274 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002275}
2276
weinig@apple.com12840dc2013-10-22 23:59:08 +00002277void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002278{
2279 if (m_floatingObjects) {
2280 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002281 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002282 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002283 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002284 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002285 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2286 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002287
2288 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2289 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2290 logicalBottom = LayoutUnit::max();
2291 else {
2292 // Special-case zero- and less-than-zero-height floats: those don't touch
2293 // the line that they're on, but it still needs to be dirtied. This is
2294 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002295 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002296 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002297 if (floatingObject.originatingLine()) {
2298 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002299 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002300 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2301 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002302 }
2303#if !ASSERT_DISABLED
zalan@apple.comd2acead2017-09-20 22:03:06 +00002304 floatingObject.clearOriginatingLine();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002305#endif
2306 }
2307 markLinesDirtyInBlockRange(0, logicalBottom);
2308 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002309 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002310 }
2311 }
2312}
2313
2314void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2315{
2316 if (!containsFloats())
2317 return;
2318
2319 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2320 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002321 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002322 m_floatingObjects->remove(curr);
2323 if (floatingObjectSet.isEmpty())
2324 break;
2325 curr = floatingObjectSet.last().get();
2326 }
2327}
2328
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002329LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2330{
2331 LayoutUnit offset = fixedOffset;
2332 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2333 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2334 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2335}
2336
2337LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2338{
2339 LayoutUnit offset = fixedOffset;
2340 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2341 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2342 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2343}
2344
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002345void RenderBlockFlow::computeLogicalLocationForFloat(FloatingObject& floatingObject, LayoutUnit& logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002346{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002347 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002348 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002349 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002350
andersca@apple.com86298632013-11-10 19:32:33 +00002351 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002352
2353 LayoutUnit floatLogicalLeft;
2354
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002355 bool insideFragmentedFlow = enclosingFragmentedFlow();
hyatt@apple.com87515262014-09-04 21:20:12 +00002356 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2357
2358 if (isInitialLetter) {
2359 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2360 if (letterClearance > 0) {
2361 logicalTopOffset += letterClearance;
2362 setLogicalHeight(logicalHeight() + letterClearance);
2363 }
2364 }
2365
akling@apple.com827be9c2013-10-29 02:58:43 +00002366 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002367 LayoutUnit heightRemainingLeft = 1;
2368 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002369 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2370 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002371 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002372 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002373 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002374 // Have to re-evaluate all of our offsets, since they may have changed.
2375 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2376 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002377 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002378 }
2379 }
andersca@apple.com86298632013-11-10 19:32:33 +00002380 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002381 } else {
2382 LayoutUnit heightRemainingLeft = 1;
2383 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002384 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2385 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002386 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002387 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002388 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002389 // Have to re-evaluate all of our offsets, since they may have changed.
2390 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2391 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002392 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002393 }
2394 }
2395 // Use the original width of the float here, since the local variable
2396 // |floatLogicalWidth| was capped to the available line width. See
2397 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002398 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002399 }
2400
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002401 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
2402 LayoutUnit childBeforeMargin = marginBeforeForChild(childBox);
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002403
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002404 if (isInitialLetter)
2405 adjustInitialLetterPosition(childBox, logicalTopOffset, childBeforeMargin);
2406
2407 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
2408 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
2409
2410 setLogicalTopForFloat(floatingObject, logicalTopOffset);
2411 setLogicalTopForChild(childBox, logicalTopOffset + childBeforeMargin);
2412
2413 setLogicalMarginsForFloat(floatingObject, childLogicalLeftMargin, childBeforeMargin);
2414}
2415
2416void RenderBlockFlow::adjustInitialLetterPosition(RenderBox& childBox, LayoutUnit& logicalTopOffset, LayoutUnit& marginBeforeOffset)
2417{
2418 const RenderStyle& style = firstLineStyle();
2419 const FontMetrics& fontMetrics = style.fontMetrics();
2420 if (!fontMetrics.hasCapHeight())
2421 return;
2422
2423 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2424 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2425
2426 // Make an adjustment to align with the cap height of a theoretical block line.
2427 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2428 logicalTopOffset += adjustment;
2429
2430 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2431 // positive for raised and negative for sunken).
2432 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2433
2434 // 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.
2435 if (dropHeightDelta < 0)
2436 marginBeforeOffset += -dropHeightDelta * heightOfLine;
2437
2438 // 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
2439 // empty lines beside the first letter.
2440 if (dropHeightDelta > 0)
2441 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002442}
2443
2444bool RenderBlockFlow::positionNewFloats()
2445{
2446 if (!m_floatingObjects)
2447 return false;
2448
2449 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2450 if (floatingObjectSet.isEmpty())
2451 return false;
2452
2453 // If all floats have already been positioned, then we have no work to do.
2454 if (floatingObjectSet.last()->isPlaced())
2455 return false;
2456
2457 // Move backwards through our floating object list until we find a float that has
2458 // already been positioned. Then we'll be able to move forward, positioning all of
2459 // the new floats that need it.
2460 auto it = floatingObjectSet.end();
2461 --it; // Go to last item.
2462 auto begin = floatingObjectSet.begin();
2463 FloatingObject* lastPlacedFloatingObject = 0;
2464 while (it != begin) {
2465 --it;
2466 if ((*it)->isPlaced()) {
2467 lastPlacedFloatingObject = it->get();
2468 ++it;
2469 break;
2470 }
2471 }
2472
2473 LayoutUnit logicalTop = logicalHeight();
2474
2475 // The float cannot start above the top position of the last positioned float.
2476 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002477 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002478
2479 auto end = floatingObjectSet.end();
2480 // Now walk through the set of unpositioned floats and place them.
2481 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002482 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002483 // The containing block is responsible for positioning floats, so if we have floats in our
2484 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002485 auto& childBox = floatingObject.renderer();
2486 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002487 continue;
2488
weinig@apple.com12840dc2013-10-22 23:59:08 +00002489 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002490
akling@apple.com827be9c2013-10-29 02:58:43 +00002491 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002492 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002493 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002494 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002495
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002496 computeLogicalLocationForFloat(floatingObject, logicalTop);
2497 LayoutUnit childLogicalTop = logicalTopForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002498
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002499 estimateFragmentRangeForBoxChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002500
hyatt@apple.comccad3742015-02-04 21:39:00 +00002501 childBox.markForPaginationRelayoutIfNeeded();
2502 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002503
zalan@apple.com4de96c52017-11-07 04:09:59 +00002504 auto* layoutState = view().frameView().layoutContext().layoutState();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002505 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002506 if (isPaginated) {
2507 // If we are unsplittable and don't fit, then we need to move down.
2508 // We include our margins as part of the unsplittable area.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002509 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, childLogicalTop - logicalTop, marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002510
2511 // See if we have a pagination strut that is making us move down further.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002512 // Note that an unsplittable child can't also have a pagination strut, so this
2513 // is exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002514 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002515 if (childBlock && childBlock->paginationStrut()) {
2516 newLogicalTop += childBlock->paginationStrut();
2517 childBlock->setPaginationStrut(0);
2518 }
2519
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002520 if (newLogicalTop != logicalTop) {
2521 floatingObject.setPaginationStrut(newLogicalTop - logicalTop);
2522 computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002523 if (childBlock)
2524 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002525 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002526 logicalTop = newLogicalTop;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002527 }
2528
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002529 if (updateFragmentRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002530 childBox.setNeedsLayout(MarkOnlyThis);
2531 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002532 }
2533 }
2534
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002535 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + (logicalTopForChild(childBox) - logicalTop) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002536
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002537 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002538
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002539 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002540 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002541 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002542 if (childBox.checkForRepaintDuringLayout())
2543 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002544 }
2545 return true;
2546}
2547
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002548void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002549{
2550 positionNewFloats();
2551 // set y position
2552 LayoutUnit newY = 0;
2553 switch (clear) {
2554 case CLEFT:
2555 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2556 break;
2557 case CRIGHT:
2558 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2559 break;
2560 case CBOTH:
2561 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002562 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002563 default:
2564 break;
2565 }
2566 if (height() < newY)
2567 setLogicalHeight(newY);
2568}
2569
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002570LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002571{
2572 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002573 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002574
2575 return fixedOffset;
2576}
2577
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002578LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002579{
2580 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002581 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002582
2583 return fixedOffset;
2584}
2585
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002586LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002587{
2588 if (!m_floatingObjects)
2589 return logicalHeight;
2590
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002591 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2592}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002593
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002594LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2595{
2596 if (!m_floatingObjects)
2597 return logicalHeight;
2598
2599 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002600}
2601
2602LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2603{
2604 if (!m_floatingObjects)
2605 return 0;
2606 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002607 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2608 auto end = floatingObjectSet.end();
2609 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002610 const auto& floatingObject = *it->get();
2611 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002612 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002613 }
2614 return lowestFloatBottom;
2615}
2616
hyatt@apple.com87515262014-09-04 21:20:12 +00002617LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2618{
2619 if (!m_floatingObjects)
2620 return 0;
2621 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002622 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2623 auto end = floatingObjectSet.end();
2624 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002625 const auto& floatingObject = *it->get();
2626 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == FIRST_LETTER && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002627 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002628 }
2629 return lowestFloatBottom;
2630}
2631
weinig@apple.com12840dc2013-10-22 23:59:08 +00002632LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002633{
2634 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002635 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002636 return 0;
2637
weinig@apple.com12840dc2013-10-22 23:59:08 +00002638 LayoutUnit childLogicalTop = child.logicalTop();
2639 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002640 LayoutUnit lowestFloatLogicalBottom = 0;
2641
2642 // Floats that will remain the child's responsibility to paint should factor into its
2643 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002644 auto childEnd = child.m_floatingObjects->set().end();
2645 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002646 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002647 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002648 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002649 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002650
2651 if (logicalBottom > logicalHeight()) {
2652 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002653 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002654 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2655 bool shouldPaint = false;
2656
2657 // The nearest enclosing layer always paints the float (so that zindex and stacking
2658 // behaves properly). We always want to propagate the desire to paint the float as
2659 // far out as we can, to the outermost block that overlaps the float, stopping only
2660 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002661 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2662 floatingObject.setShouldPaint(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002663 shouldPaint = true;
2664 }
2665 // We create the floating object list lazily.
2666 if (!m_floatingObjects)
2667 createFloatingObjects();
2668
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002669 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002670 }
2671 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002672 const auto& renderer = floatingObject.renderer();
2673 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2674 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002675 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2676 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2677 // layer.
2678 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2679 // it should paint.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002680 floatingObject.setShouldPaint(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002681 }
2682
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002683 // Since the float doesn't overhang, it didn't get put into our list. We need to add its overflow in to the child now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002684 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002685 child.addOverflowFromChild(&renderer, floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002686 }
2687 }
2688 return lowestFloatLogicalBottom;
2689}
2690
weinig@apple.com12840dc2013-10-22 23:59:08 +00002691bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002692{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002693 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002694 return false;
2695
2696 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002697 const auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002698 if (it == floatingObjectSet.end())
2699 return false;
2700
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002701 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002702}
2703
hyatt@apple.com21c60802015-04-01 18:10:32 +00002704void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002705{
2706 ASSERT(!avoidsFloats());
2707
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002708 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2709 if (createsNewFormattingContext())
2710 return;
2711
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002712 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2713 if (!prev->m_floatingObjects)
2714 return;
2715
2716 logicalLeftOffset += marginLogicalLeft();
2717
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002718 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2719 auto prevEnd = prevSet.end();
2720 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002721 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002722 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002723 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002724 // We create the floating object list lazily.
2725 if (!m_floatingObjects)
2726 createFloatingObjects();
2727
2728 // Applying the child's margin makes no sense in the case where the child was passed in.
2729 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2730 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2731 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2732 // will get applied twice.
2733 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002734 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2735 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002736
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002737 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002738 }
2739 }
2740 }
2741}
2742
2743void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2744{
2745 if (!everHadLayout() && !containsFloats())
2746 return;
2747
2748 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2749 setChildNeedsLayout(markParents);
2750
2751 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002752 removeFloatingObject(*floatToRemove);
hyatt@apple.com11a5e5c2016-05-19 21:51:31 +00002753 else if (childrenInline())
hyatt@apple.com00e93142016-05-18 18:59:40 +00002754 return;
2755
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002756 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002757 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2758 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2759 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002760 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002761 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2762 block.setChildNeedsLayout(markParents);
2763 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002764 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002765 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002766 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2767 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002768 }
2769}
2770
2771void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2772{
2773 if (!m_floatingObjects)
2774 return;
2775
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002776 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2777 auto end = floatingObjectSet.end();
2778
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002779 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002780 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002781 continue;
2782
cdumez@apple.come9437792014-10-08 23:33:43 +00002783 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002784 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2785 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002786 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002787 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002788 if (nextBlock.containsFloat(floatingBox))
2789 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002790 }
2791 }
2792}
2793
zalan@apple.com6816b132015-10-17 19:14:53 +00002794LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002795{
akling@apple.com827be9c2013-10-29 02:58:43 +00002796 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002797 return point;
2798
2799 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2800 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2801 // case.
2802 if (isHorizontalWritingMode())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002803 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * child.locationOffsetOfBorderBox().height());
2804 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * child.locationOffsetOfBorderBox().width(), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002805}
2806
weinig@apple.com12840dc2013-10-22 23:59:08 +00002807LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002808{
2809 // There is no need to compute clearance if we have no floats.
2810 if (!containsFloats())
2811 return 0;
2812
2813 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002814 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002815 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002816 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002817 case CNONE:
2818 break;
2819 case CLEFT:
2820 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2821 break;
2822 case CRIGHT:
2823 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2824 break;
2825 case CBOTH:
2826 logicalBottom = lowestFloatLogicalBottom();
2827 break;
2828 }
2829
2830 // 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 +00002831 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002832 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002833 LayoutUnit newLogicalTop = logicalTop;
2834 while (true) {
zalan@apple.com64761fe2016-03-02 21:42:22 +00002835 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002836 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2837 return newLogicalTop - logicalTop;
2838
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002839 RenderFragmentContainer* fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2840 LayoutRect borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002841 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2842
2843 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002844 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2845 LayoutUnit childOldMarginLeft = child.marginLeft();
2846 LayoutUnit childOldMarginRight = child.marginRight();
2847 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002848
weinig@apple.com12840dc2013-10-22 23:59:08 +00002849 child.setLogicalTop(newLogicalTop);
2850 child.updateLogicalWidth();
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002851 fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2852 borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002853 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2854
weinig@apple.com12840dc2013-10-22 23:59:08 +00002855 child.setLogicalTop(childOldLogicalTop);
2856 child.setLogicalWidth(childOldLogicalWidth);
2857 child.setMarginLeft(childOldMarginLeft);
2858 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002859
2860 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2861 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2862 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2863 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2864 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002865 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002866 return newLogicalTop - logicalTop;
2867 }
2868
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002869 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002870 ASSERT(newLogicalTop >= logicalTop);
2871 if (newLogicalTop < logicalTop)
2872 break;
2873 }
2874 ASSERT_NOT_REACHED();
2875 }
2876 return result;
2877}
2878
2879bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2880{
2881 if (!m_floatingObjects)
2882 return false;
2883
2884 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002885 if (is<RenderView>(*this))
2886 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002887
2888 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2889 auto begin = floatingObjectSet.begin();
2890 for (auto it = floatingObjectSet.end(); it != begin;) {
2891 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002892 const auto& floatingObject = *it->get();
2893 auto& renderer = floatingObject.renderer();
2894 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002895 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002896 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002897 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2898 return true;
2899 }
2900 }
2901 }
2902
2903 return false;
2904}
2905
weinig@apple.com611b9292013-10-20 22:57:54 +00002906bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2907{
2908 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002909
darin@apple.come1be6ca2014-04-28 04:19:10 +00002910 if (auto simpleLineLayout = this->simpleLineLayout())
2911 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002912
weinig@apple.com611b9292013-10-20 22:57:54 +00002913 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2914}
2915
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002916void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2917{
akling@apple.com827be9c2013-10-29 02:58:43 +00002918 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002919 return;
2920
2921 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2922 // for either overflow or translations via relative positioning.
2923 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002924 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2925
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002926 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002927 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002928 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002929 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002930 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002931 }
2932 } else {
2933 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2934 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002935 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2936 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002937 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002938 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002939 left = std::min(left, x + obj->x());
2940 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002941 }
2942 }
2943 }
2944 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002945
2946 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002947 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2948 auto end = floatingObjectSet.end();
2949 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002950 const auto& floatingObject = *it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002951 // Only examine the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002952 if (floatingObject.shouldPaint()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002953 LayoutUnit floatLeft = floatingObject.translationOffsetToAncestor().width();
zalan@apple.com6816b132015-10-17 19:14:53 +00002954 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002955 left = std::min(left, floatLeft);
2956 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002957 }
2958 }
2959 }
2960}
2961
2962void RenderBlockFlow::fitBorderToLinesIfNeeded()
2963{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002964 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002965 return;
2966
2967 // Walk any normal flow lines to snugly fit.
2968 LayoutUnit left = LayoutUnit::max();
2969 LayoutUnit right = LayoutUnit::min();
2970 LayoutUnit oldWidth = contentWidth();
2971 adjustForBorderFit(0, left, right);
2972
2973 // Clamp to our existing edges. We can never grow. We only shrink.
2974 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2975 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002976 left = std::min(rightEdge, std::max(leftEdge, left));
2977 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002978
2979 LayoutUnit newContentWidth = right - left;
2980 if (newContentWidth == oldWidth)
2981 return;
2982
2983 setOverrideLogicalContentWidth(newContentWidth);
2984 layoutBlock(false);
2985 clearOverrideLogicalContentWidth();
2986}
2987
2988void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2989{
2990 if (logicalTop >= logicalBottom)
2991 return;
2992
antti@apple.combe9d3e12014-05-11 09:42:47 +00002993 // Floats currently affect the choice whether to use simple line layout path.
2994 if (m_simpleLineLayout) {
2995 invalidateLineLayoutPath();
2996 return;
2997 }
2998
weinig@apple.com611b9292013-10-20 22:57:54 +00002999 RootInlineBox* lowestDirtyLine = lastRootBox();
3000 RootInlineBox* afterLowest = lowestDirtyLine;
3001 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3002 afterLowest = lowestDirtyLine;
3003 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3004 }
3005
3006 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3007 afterLowest->markDirty();
3008 afterLowest = afterLowest->prevRootBox();
3009 }
3010}
3011
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003012std::optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003013{
3014 if (isWritingModeRoot() && !isRubyRun())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003015 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003016
3017 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003018 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003019
antti@apple.com940f5872013-10-24 20:31:11 +00003020 if (!hasLines())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003021 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003022
darin@apple.come1be6ca2014-04-28 04:19:10 +00003023 if (auto simpleLineLayout = this->simpleLineLayout())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003024 return std::optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003025
akling@apple.comee3c8df2013-11-06 08:09:44 +00003026 ASSERT(firstRootBox());
3027 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003028}
3029
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003030std::optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003031{
3032 if (isWritingModeRoot() && !isRubyRun())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003033 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003034
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003035 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3036 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3037 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003038 if (!childrenInline()) {
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003039 std::optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003040 if (!inlineBlockBaseline)
3041 return inlineBlockBaseline;
3042 lastBaseline = inlineBlockBaseline.value();
3043 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003044 if (!hasLines()) {
3045 if (!hasLineIfEmpty())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003046 return std::optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003047 const auto& fontMetrics = firstLineStyle().fontMetrics();
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003048 return std::optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003049 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003050 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003051 }
3052
3053 if (auto simpleLineLayout = this->simpleLineLayout())
3054 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3055 else {
3056 bool isFirstLine = lastRootBox() == firstRootBox();
3057 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3058 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3059 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003060 }
3061 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3062 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3063 // enough with the spec to not cause tons of breakages).
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003064 return std::optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003065}
3066
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003067void RenderBlockFlow::setSelectionState(SelectionState state)
3068{
3069 if (state != SelectionNone)
3070 ensureLineBoxes();
3071 RenderBoxModelObject::setSelectionState(state);
3072}
3073
weinig@apple.com12840dc2013-10-22 23:59:08 +00003074GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003075 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3076{
antti@apple.comfea51992013-10-28 13:39:23 +00003077 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003078
weinig@apple.com611b9292013-10-20 22:57:54 +00003079 GapRects result;
3080
3081 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3082
antti@apple.com0e632aa2013-10-22 21:03:38 +00003083 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003084 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003085 // Update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this case.
weinig@apple.com611b9292013-10-20 22:57:54 +00003086 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3087 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3088 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3089 }
3090 return result;
3091 }
3092
3093 RootInlineBox* lastSelectedLine = 0;
3094 RootInlineBox* curr;
3095 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3096
3097 // Now paint the gaps for the lines.
3098 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3099 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3100 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3101
3102 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003103 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003104 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3105
3106 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3107 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003108 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003109 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3110 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3111 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3112
3113 lastSelectedLine = curr;
3114 }
3115
3116 if (containsStart && !lastSelectedLine)
3117 // VisibleSelection must start just after our last line.
3118 lastSelectedLine = lastRootBox();
3119
3120 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003121 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003122 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3123 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3124 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3125 }
3126 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003127}
3128
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003129bool RenderBlockFlow::needsLayoutAfterFragmentRangeChange() const
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003130{
3131 // A block without floats or that expands to enclose them won't need a relayout
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003132 // after a fragment range change. There is no overflow content needing relayout
3133 // in the fragment chain because the fragment range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003134 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003135 return false;
3136
3137 return true;
3138}
3139
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003140void RenderBlockFlow::updateLogicalHeight()
3141{
3142 RenderBlock::updateLogicalHeight();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003143}
3144
zalan@apple.com624c2642017-10-05 14:04:27 +00003145void RenderBlockFlow::setMultiColumnFlow(RenderMultiColumnFlow& fragmentedFlow)
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003146{
zalan@apple.com624c2642017-10-05 14:04:27 +00003147 ASSERT(!hasRareBlockFlowData() || !rareBlockFlowData()->m_multiColumnFlow);
3148 ensureRareBlockFlowData().m_multiColumnFlow = makeWeakPtr(fragmentedFlow);
3149}
3150
3151void RenderBlockFlow::clearMultiColumnFlow()
3152{
3153 ASSERT(hasRareBlockFlowData());
3154 ASSERT(rareBlockFlowData()->m_multiColumnFlow);
3155 rareBlockFlowData()->m_multiColumnFlow.clear();
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003156}
3157
akling@apple.com525dae62014-01-03 20:22:09 +00003158static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003159{
akling@apple.com38f0a652014-02-06 21:24:17 +00003160 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003161}
3162
3163RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3164{
3165 ASSERT(i >= 0);
3166
akling@apple.com827be9c2013-10-29 02:58:43 +00003167 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003168 return nullptr;
3169
3170 if (childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003171 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003172 if (!i--)
3173 return box;
3174 }
akling@apple.com525dae62014-01-03 20:22:09 +00003175 return nullptr;
3176 }
3177
3178 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3179 if (!shouldCheckLines(blockFlow))
3180 continue;
3181 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3182 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003183 }
3184
3185 return nullptr;
3186}
3187
3188int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3189{
akling@apple.com827be9c2013-10-29 02:58:43 +00003190 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003191 return 0;
3192
3193 int count = 0;
3194
3195 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003196 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003197 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003198 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003199 }
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003200 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3201 ++count;
weinig@apple.com17140912013-10-19 19:55:40 +00003202 if (box == stopRootInlineBox) {
3203 if (found)
3204 *found = true;
3205 break;
3206 }
3207 }
akling@apple.com525dae62014-01-03 20:22:09 +00003208 return count;
3209 }
3210
3211 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3212 if (!shouldCheckLines(blockFlow))
3213 continue;
3214 bool recursiveFound = false;
3215 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3216 if (recursiveFound) {
3217 if (found)
3218 *found = true;
3219 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003220 }
3221 }
3222
3223 return count;
3224}
3225
3226static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3227{
akling@apple.com827be9c2013-10-29 02:58:43 +00003228 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003229 return -1;
3230
3231 if (block.childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003232 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003233 if (++count == lineCount)
3234 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3235 }
3236 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003237 RenderBox* normalFlowChildWithoutLines = nullptr;
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003238 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003239 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3240 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003241 if (result != -1)
3242 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003243 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003244 normalFlowChildWithoutLines = obj;
3245 }
3246 if (normalFlowChildWithoutLines && !lineCount)
3247 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3248 }
3249
3250 return -1;
3251}
3252
3253int RenderBlockFlow::heightForLineCount(int lineCount)
3254{
3255 int count = 0;
3256 return getHeightForLineCount(*this, lineCount, true, count);
3257}
3258
3259void RenderBlockFlow::clearTruncation()
3260{
akling@apple.com827be9c2013-10-29 02:58:43 +00003261 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003262 return;
3263
3264 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003265 ensureLineBoxes();
3266
weinig@apple.com17140912013-10-19 19:55:40 +00003267 setHasMarkupTruncation(false);
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003268 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
weinig@apple.com17140912013-10-19 19:55:40 +00003269 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003270 return;
3271 }
3272
3273 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3274 if (shouldCheckLines(blockFlow))
3275 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003276 }
3277}
3278
weinig@apple.com3f23b382013-10-19 20:26:58 +00003279bool RenderBlockFlow::containsNonZeroBidiLevel() const
3280{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003281 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3282 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003283 if (box->bidiLevel())
3284 return true;
3285 }
3286 }
3287 return false;
3288}
3289
weinig@apple.com611b9292013-10-20 22:57:54 +00003290Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3291{
3292 if (!box)
3293 return Position();
3294
3295 if (!box->renderer().nonPseudoNode())
3296 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3297
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003298 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003299 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3300
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003301 auto& textBox = downcast<InlineTextBox>(*box);
3302 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003303}
3304
enrica@apple.com0db51a62016-04-27 23:53:08 +00003305RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
3306{
3307 // A light, non-recursive version of RenderBlock::positionForCoordinates that looks at
3308 // whether a point lies within the gaps between its root line boxes, to be called against
3309 // a node returned from elementAtPoint. We make the assumption that either the node or one
3310 // of its immediate children contains the root line boxes in question.
3311 // See <rdar://problem/6824650> for context.
3312
3313 RenderBlock* block = this;
3314
3315 FloatPoint localPoint = block->absoluteToLocal(point);
3316
3317 if (!block->childrenInline()) {
3318 // Look among our immediate children for an alternate box that contains the point.
3319 for (RenderBox* child = block->firstChildBox(); child; child = child->nextSiblingBox()) {
3320 if (!child->height() || child->style().visibility() != WebCore::VISIBLE || child->isFloatingOrOutOfFlowPositioned())
3321 continue;
3322 float top = child->y();
3323
3324 RenderBox* nextChild = child->nextSiblingBox();
3325 while (nextChild && nextChild->isFloatingOrOutOfFlowPositioned())
3326 nextChild = nextChild->nextSiblingBox();
3327 if (!nextChild) {
3328 if (localPoint.y() >= top) {
3329 block = downcast<RenderBlock>(child);
3330 break;
3331 }
3332 continue;
3333 }
3334
3335 float bottom = nextChild->y();
3336
3337 if (localPoint.y() >= top && localPoint.y() < bottom && is<RenderBlock>(*child)) {
3338 block = downcast<RenderBlock>(child);
3339 break;
3340 }
3341 }
3342
3343 if (!block->childrenInline())
3344 return nullptr;
3345
3346 localPoint = block->absoluteToLocal(point);
3347 }
3348
3349 RenderBlockFlow& blockFlow = downcast<RenderBlockFlow>(*block);
3350
3351 // Only check the gaps between the root line boxes. We deliberately ignore overflow because
3352 // experience has shown that hit tests on an exploded text node can fail when within the
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003353 // overflow fragment.
enrica@apple.com0db51a62016-04-27 23:53:08 +00003354 for (RootInlineBox* current = blockFlow.firstRootBox(); current && current != blockFlow.lastRootBox(); current = current->nextRootBox()) {
3355 float currentBottom = current->y() + current->logicalHeight();
3356 if (localPoint.y() < currentBottom)
3357 return nullptr;
3358
3359 RootInlineBox* next = current->nextRootBox();
3360 float nextTop = next->y();
3361 if (localPoint.y() < nextTop) {
3362 InlineBox* inlineBox = current->closestLeafChildForLogicalLeftPosition(localPoint.x());
3363 if (inlineBox && inlineBox->behavesLikeText() && is<RenderText>(inlineBox->renderer()))
3364 return &downcast<RenderText>(inlineBox->renderer());
3365 }
3366 }
3367 return nullptr;
3368}
3369
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003370VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer* fragment)
weinig@apple.com611b9292013-10-20 22:57:54 +00003371{
3372 ASSERT(childrenInline());
3373
antti@apple.com940f5872013-10-24 20:31:11 +00003374 ensureLineBoxes();
3375
weinig@apple.com611b9292013-10-20 22:57:54 +00003376 if (!firstRootBox())
3377 return createVisiblePosition(0, DOWNSTREAM);
3378
akling@apple.com827be9c2013-10-29 02:58:43 +00003379 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3380 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003381
3382 // look for the closest line box in the root box which is at the passed-in y coordinate
3383 InlineBox* closestBox = 0;
3384 RootInlineBox* firstRootBoxWithChildren = 0;
3385 RootInlineBox* lastRootBoxWithChildren = 0;
3386 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003387 if (fragment && root->containingFragment() != fragment)
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003388 continue;
3389
weinig@apple.com611b9292013-10-20 22:57:54 +00003390 if (!root->firstLeafChild())
3391 continue;
3392 if (!firstRootBoxWithChildren)
3393 firstRootBoxWithChildren = root;
3394
3395 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3396 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3397 break;
3398
3399 lastRootBoxWithChildren = root;
3400
3401 // check if this root line box is located at this y coordinate
3402 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3403 if (linesAreFlipped) {
3404 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3405 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3406 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3407
3408 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3409 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3410 continue;
3411 }
3412 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3413 if (closestBox)
3414 break;
3415 }
3416 }
3417
3418 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3419
3420 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3421 // y coordinate is below last root line box, pretend we hit it
3422 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3423 }
3424
3425 if (closestBox) {
3426 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003427 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003428 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3429 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3430 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3431 if (box->isLineBreak()) {
3432 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3433 box = newBox;
3434 }
3435 // y coordinate is above first root line box, so return the start of the first
3436 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3437 }
3438 }
3439
3440 // pass the box a top position that is inside it
3441 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3442 if (!isHorizontalWritingMode())
3443 point = point.transposedPoint();
3444 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003445 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003446 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003447 }
3448
3449 if (lastRootBoxWithChildren) {
3450 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3451 ASSERT(moveCaretToBoundary);
3452 InlineBox* logicallyLastBox;
3453 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3454 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3455 }
3456
3457 // Can't reach this. We have a root line box, but it has no kids.
3458 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3459 // seems to hit this code path.
3460 return createVisiblePosition(0, DOWNSTREAM);
3461}
3462
zalan@apple.com0d5951b2017-02-19 16:24:20 +00003463Position RenderBlockFlow::positionForPoint(const LayoutPoint& point)
3464{
3465 // FIXME: It supports single text child only (which is the majority of simple line layout supported content at this point).
3466 if (!simpleLineLayout() || firstChild() != lastChild() || !is<RenderText>(firstChild()))
3467 return positionForPoint(point, nullptr).deepEquivalent();
3468 return downcast<RenderText>(*firstChild()).positionForPoint(point);
3469}
3470
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003471VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer*)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003472{
antti@apple.come0e8a562017-09-21 18:29:47 +00003473 return RenderBlock::positionForPoint(point, nullptr);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003474}
3475
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003476void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
weinig@apple.com611b9292013-10-20 22:57:54 +00003477{
antti@apple.com940f5872013-10-24 20:31:11 +00003478 ASSERT(childrenInline());
weinig@apple.com611b9292013-10-20 22:57:54 +00003479 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003480 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3481 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003482 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3483 if (!rect.isEmpty())
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003484 rects.append(rect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003485 }
3486}
3487
3488void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3489{
3490 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003491
darin@apple.come1be6ca2014-04-28 04:19:10 +00003492 if (auto simpleLineLayout = this->simpleLineLayout()) {
3493 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003494 return;
3495 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003496 m_lineBoxes.paint(this, paintInfo, paintOffset);
3497}
3498
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003499bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003500{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003501 if (!multiColumnFlow() || !multiColumnFlow()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003502 return false;
3503
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003504 multiColumnFlow()->setNeedsHeightsRecalculation(false);
3505 multiColumnFlow()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003506
3507 bool needsRelayout;
3508 bool neededRelayout = false;
3509 bool firstPass = true;
3510 do {
3511 // Column heights may change here because of balancing. We may have to do multiple layout
3512 // passes, depending on how the contents is fitted to the changed column heights. In most
3513 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3514 // passes than that, though, but the number of retries should not exceed the number of
3515 // columns, unless we have a bug.
3516 needsRelayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003517 for (RenderMultiColumnSet* multicolSet = multiColumnFlow()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003518 if (multicolSet->recalculateColumnHeight(firstPass))
3519 needsRelayout = true;
3520 if (needsRelayout) {
3521 // Once a column set gets a new column height, that column set and all successive column
3522 // sets need to be laid out over again, since their logical top will be affected by
3523 // this, and therefore their column heights may change as well, at least if the multicol
3524 // height is constrained.
3525 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003526 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003527 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003528 if (needsRelayout) {
3529 // Layout again. Column balancing resulted in a new height.
3530 neededRelayout = true;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003531 multiColumnFlow()->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003532 setChildNeedsLayout(MarkOnlyThis);
3533 if (firstPass)
3534 statePusher.pop();
3535 layoutBlock(false);
3536 }
3537 firstPass = false;
3538 } while (needsRelayout);
3539
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003540 multiColumnFlow()->setInBalancingPass(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003541
3542 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003543}
3544
antti@apple.com940f5872013-10-24 20:31:11 +00003545bool RenderBlockFlow::hasLines() const
3546{
zalan@apple.coma2fe1762016-08-24 18:33:43 +00003547 if (!childrenInline())
3548 return false;
antti@apple.com940f5872013-10-24 20:31:11 +00003549
darin@apple.come1be6ca2014-04-28 04:19:10 +00003550 if (auto simpleLineLayout = this->simpleLineLayout())
3551 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003552
3553 return lineBoxes().firstLineBox();
3554}
3555
antti@apple.com9e891c82014-05-22 06:12:34 +00003556void RenderBlockFlow::invalidateLineLayoutPath()
3557{
akling@apple.coma12fee22015-02-01 02:58:13 +00003558 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003559 case UndeterminedPath:
3560 case ForceLineBoxesPath:
3561 ASSERT(!m_simpleLineLayout);
3562 return;
3563 case LineBoxesPath:
3564 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003565 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003566 return;
3567 case SimpleLinesPath:
3568 // The simple line layout may have become invalid.
3569 m_simpleLineLayout = nullptr;
akling@apple.coma12fee22015-02-01 02:58:13 +00003570 setLineLayoutPath(UndeterminedPath);
zalan@apple.comde191042017-06-06 19:35:56 +00003571 if (needsLayout())
3572 return;
3573 // FIXME: We should just kick off a subtree layout here (if needed at all) see webkit.org/b/172947.
3574 setNeedsLayout();
antti@apple.com9e891c82014-05-22 06:12:34 +00003575 return;
3576 }
3577 ASSERT_NOT_REACHED();
3578}
3579
zalan@apple.come37da962014-12-11 03:29:29 +00003580void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003581{
zalan@apple.come37da962014-12-11 03:29:29 +00003582 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3583 if (needsLayout) {
3584 deleteLineBoxesBeforeSimpleLineLayout();
3585 m_simpleLineLayout = SimpleLineLayout::create(*this);
3586 }
zalan@apple.com4de96c52017-11-07 04:09:59 +00003587 if (view().frameView().layoutContext().layoutState() && view().frameView().layoutContext().layoutState()->isPaginated()) {
zalan@apple.com5cd09e52017-02-25 02:14:40 +00003588 m_simpleLineLayout->setIsPaginated();
3589 SimpleLineLayout::adjustLinePositionsForPagination(*m_simpleLineLayout, *this);
3590 }
zalan@apple.comd6ab7b52016-11-01 05:35:48 +00003591 for (auto& renderer : childrenOfType<RenderObject>(*this))
3592 renderer.clearNeedsLayout();
antti@apple.com940f5872013-10-24 20:31:11 +00003593 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00003594 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003595 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003596 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003597 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003598 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3599}
3600
3601void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3602{
akling@apple.coma12fee22015-02-01 02:58:13 +00003603 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003604 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003605 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3606 if (is<RenderText>(renderer))
3607 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3608 else if (is<RenderLineBreak>(renderer))
3609 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3610 else
3611 ASSERT_NOT_REACHED();
3612 }
antti@apple.com940f5872013-10-24 20:31:11 +00003613}
3614
3615void RenderBlockFlow::ensureLineBoxes()
3616{
akling@apple.coma12fee22015-02-01 02:58:13 +00003617 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003618 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003619 return;
zalan@apple.comfa5add62017-02-22 19:33:02 +00003620 bool isPaginated = m_simpleLineLayout->isPaginated();
antti@apple.comfea51992013-10-28 13:39:23 +00003621 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003622
3623#if !ASSERT_DISABLED
3624 LayoutUnit oldHeight = logicalHeight();
3625#endif
3626 bool didNeedLayout = needsLayout();
3627
3628 bool relayoutChildren = false;
3629 LayoutUnit repaintLogicalTop;
3630 LayoutUnit repaintLogicalBottom;
zalan@apple.comfa5add62017-02-22 19:33:02 +00003631 if (isPaginated) {
zalan@apple.com6c04c202017-05-01 00:15:38 +00003632 PaginatedLayoutStateMaintainer state(*this);
zalan@apple.comfa5add62017-02-22 19:33:02 +00003633 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
zalan@apple.come9f08212017-04-27 11:02:09 +00003634 // This matches relayoutToAvoidWidows.
3635 if (shouldBreakAtLineToAvoidWidow())
3636 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
zalan@apple.comb16bcdc2017-07-21 21:04:43 +00003637 // FIXME: This is needed as long as simple and normal line layout produce different line breakings.
3638 repaint();
zalan@apple.comfa5add62017-02-22 19:33:02 +00003639 } else
3640 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +00003641
3642 updateLogicalHeight();
3643 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3644
3645 if (!didNeedLayout)
3646 clearNeedsLayout();
3647}
3648
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003649#if ENABLE(TREE_DEBUGGING)
don.olmstead@sony.comd57eb472017-08-10 01:15:14 +00003650void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003651{
weinig@apple.com611b9292013-10-20 22:57:54 +00003652 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.com360de752017-07-06 21:13:24 +00003653 root->outputLineTreeAndMark(stream, markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003654
3655 if (auto simpleLineLayout = this->simpleLineLayout())
zalan@apple.com360de752017-07-06 21:13:24 +00003656 SimpleLineLayout::outputLineLayoutForFlow(stream, *this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003657}
3658#endif
3659
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003660RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3661{
3662 if (hasRareBlockFlowData())
3663 return *m_rareBlockFlowData;
3664 materializeRareBlockFlowData();
3665 return *m_rareBlockFlowData;
3666}
3667
3668void RenderBlockFlow::materializeRareBlockFlowData()
3669{
3670 ASSERT(!hasRareBlockFlowData());
3671 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3672}
3673
dbates@webkit.org102013c2016-09-26 21:51:25 +00003674#if ENABLE(TEXT_AUTOSIZING)
cdumez@apple.com83102df2016-05-19 19:09:41 +00003675static inline bool isVisibleRenderText(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003676{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003677 if (!is<RenderText>(renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003678 return false;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003679
3680 auto& renderText = downcast<RenderText>(renderer);
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003681 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003682}
3683
cdumez@apple.com83102df2016-05-19 19:09:41 +00003684static inline bool resizeTextPermitted(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003685{
3686 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
cdumez@apple.com83102df2016-05-19 19:09:41 +00003687 for (auto* ancestor = renderer.parent(); ancestor; ancestor = ancestor->parent()) {
aestes@apple.com6751d842014-01-12 02:51:25 +00003688 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.com83102df2016-05-19 19:09:41 +00003689 if (is<HTMLElement>(ancestor->element()) && !ancestor->element()->isInShadowTree()) {
3690 auto& element = downcast<HTMLElement>(*ancestor->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003691 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003692 }
aestes@apple.com6751d842014-01-12 02:51:25 +00003693 }
3694 return true;
3695}
3696
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003697int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003698{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003699 if (style().visibility() != VISIBLE)
3700 return 0;
3701 if (childrenInline())
3702 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003703 // Only descend into list items.
3704 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003705 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3706 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003707 return count;
3708}
3709
cdumez@apple.com83102df2016-05-19 19:09:41 +00003710static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003711{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003712 if (!renderer.isRenderBlock())
aestes@apple.com6751d842014-01-12 02:51:25 +00003713 return true;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003714 if (renderer.isListItem())
3715 return renderer.style().height().type() != Fixed;
aestes@apple.com6751d842014-01-12 02:51:25 +00003716 return false;
3717}
3718
3719// For now, we auto size single lines of text the same as multiple lines.
3720// We've been experimenting with low values for single lines of text.
3721static inline float oneLineTextMultiplier(float specifiedSize)
3722{
3723 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3724}
3725
3726static inline float textMultiplier(float specifiedSize)
3727{
3728 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3729}
3730
3731void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3732{
simon.fraser@apple.com36676e52016-05-07 00:05:58 +00003733 LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
3734
aestes@apple.com6751d842014-01-12 02:51:25 +00003735 // Don't do any work if the block is smaller than the visible area.
3736 if (visibleWidth >= width())
3737 return;
3738
3739 unsigned lineCount;
3740 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003741 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003742 if (!count)
3743 lineCount = NO_LINE;
3744 else if (count == 1)
3745 lineCount = ONE_LINE;
3746 else
3747 lineCount = MULTI_LINE;
3748 } else
3749 lineCount = m_lineCountForTextAutosizing;
3750
3751 ASSERT(lineCount != NOT_SET);
3752 if (lineCount == NO_LINE)
3753 return;
3754
3755 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3756 float scale = visibleWidth / actualWidth;
3757 float minFontSize = roundf(size / scale);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003758
3759 for (auto* descendant = RenderObjectTraversal::firstChild(*this); descendant; ) {
3760 if (!isNonBlocksOrNonFixedHeightListItems(*descendant)) {
3761 descendant = RenderObjectTraversal::nextSkippingChildren(*descendant, this);
3762 continue;
aestes@apple.com6751d842014-01-12 02:51:25 +00003763 }
cdumez@apple.com83102df2016-05-19 19:09:41 +00003764 if (!isVisibleRenderText(*descendant) || !resizeTextPermitted(*descendant)) {
3765 descendant = RenderObjectTraversal::next(*descendant, this);
3766 continue;
3767 }
3768
3769 auto& text = downcast<RenderText>(*descendant);
3770 auto& oldStyle = text.style();
3771 auto& fontDescription = oldStyle.fontDescription();
3772 float specifiedSize = fontDescription.specifiedSize();
3773 float scaledSize = roundf(specifiedSize * scale);
3774 if (scaledSize > 0 && scaledSize < minFontSize) {
3775 // 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.
3776 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3777 if (m_lineCountForTextAutosizing == NOT_SET)
3778 m_lineCountForTextAutosizing = lineCount;
3779 if (m_widthForTextAutosizing == -1)
3780 m_widthForTextAutosizing = actualWidth;
3781
3782 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3783 float candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
3784 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
antti@apple.com4918b4d2017-08-14 13:20:47 +00003785 document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003786 }
3787
3788 descendant = RenderObjectTraversal::nextSkippingChildren(text, this);
aestes@apple.com6751d842014-01-12 02:51:25 +00003789 }
3790}
dbates@webkit.org102013c2016-09-26 21:51:25 +00003791#endif // ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +00003792
hyatt@apple.com80914862017-03-06 18:00:35 +00003793void RenderBlockFlow::layoutExcludedChildren(bool relayoutChildren)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003794{
hyatt@apple.com80914862017-03-06 18:00:35 +00003795 RenderBlock::layoutExcludedChildren(relayoutChildren);
3796
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003797 auto* fragmentedFlow = multiColumnFlow();
3798 if (!fragmentedFlow)
hyatt@apple.com80914862017-03-06 18:00:35 +00003799 return;
3800
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003801 fragmentedFlow->setIsExcludedFromNormalLayout(true);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003802
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003803 setLogicalTopForChild(*fragmentedFlow, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003804
3805 if (relayoutChildren)
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003806 fragmentedFlow->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003807
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003808 if (fragmentedFlow->needsLayout()) {
3809 for (RenderMultiColumnSet* columnSet = fragmentedFlow->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3810 columnSet->prepareForLayout(!fragmentedFlow->inBalancingPass());
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003811
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003812 fragmentedFlow->invalidateFragments(MarkOnlyThis);
3813 fragmentedFlow->setNeedsHeightsRecalculation(true);
3814 fragmentedFlow->layout();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003815 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003816 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3817 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3818 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3819 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3820 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3821 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3822 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3823 // runs get deleted right after every pass.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003824 fragmentedFlow->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003825 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003826 determineLogicalLeftPositionForChild(*fragmentedFlow);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003827}
3828
antti@apple.com6a146b62017-09-30 06:45:59 +00003829void RenderBlockFlow::addChild(RenderPtr<RenderObject> newChild, RenderObject* beforeChild)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003830{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003831 if (multiColumnFlow() && (!isFieldset() || !newChild->isLegend()))
antti@apple.com6a146b62017-09-30 06:45:59 +00003832 return multiColumnFlow()->addChild(WTFMove(newChild), beforeChild);
zalan@apple.comba6049c2017-01-28 16:26:48 +00003833 auto* beforeChildOrPlaceholder = beforeChild;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003834 if (auto* containingFragmentedFlow = enclosingFragmentedFlow())
3835 beforeChildOrPlaceholder = containingFragmentedFlow->resolveMovedChild(beforeChild);
antti@apple.com6a146b62017-09-30 06:45:59 +00003836 RenderBlock::addChild(WTFMove(newChild), beforeChildOrPlaceholder);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003837}
3838
antti@apple.com6a146b62017-09-30 06:45:59 +00003839RenderPtr<RenderObject> RenderBlockFlow::takeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003840{
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +00003841 if (!renderTreeBeingDestroyed()) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003842 RenderFragmentedFlow* fragmentedFlow = multiColumnFlow();
3843 if (fragmentedFlow && fragmentedFlow != &oldChild)
3844 fragmentedFlow->fragmentedFlowRelativeWillBeRemoved(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003845 }
antti@apple.com6a146b62017-09-30 06:45:59 +00003846 return RenderBlock::takeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003847}
3848
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003849void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003850{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003851 // If we don't use columns or flow threads, then bail.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003852 if (!isRenderFragmentedFlow() && !multiColumnFlow())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003853 return;
3854
3855 // We don't actually update any of the variables. We just subclassed to adjust our column height.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003856 if (RenderMultiColumnFlow* fragmentedFlow = multiColumnFlow()) {
zalan@apple.com53e79072016-12-12 20:17:50 +00003857 LayoutUnit newColumnHeight;
3858 if (hasDefiniteLogicalHeight() || view().frameView().pagination().mode != Pagination::Unpaginated) {
zalan@apple.comcca4b692016-12-16 04:37:28 +00003859 auto computedValues = computeLogicalHeight(LayoutUnit(), logicalTop());
zalan@apple.com53e79072016-12-12 20:17:50 +00003860 newColumnHeight = std::max<LayoutUnit>(computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(), 0);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003861 if (fragmentedFlow->columnHeightAvailable() != newColumnHeight)
zalan@apple.com53e79072016-12-12 20:17:50 +00003862 relayoutChildren = true;
3863 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003864 fragmentedFlow->setColumnHeightAvailable(newColumnHeight);
3865 } else if (is<RenderFragmentedFlow>(*this)) {
3866 RenderFragmentedFlow& fragmentedFlow = downcast<RenderFragmentedFlow>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003867
3868 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3869 // is known. The page logical height thing in LayoutState is meaningless for flow
3870 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3871 // thread), but as long as it is used universally as a means to determine whether page
3872 // height is known or not, we need this. Page height is unknown when column balancing is
3873 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3874 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3875 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
zalan@apple.comfa5add62017-02-22 19:33:02 +00003876 // hack once the old multicol implementation is gone (see also RenderView::pushLayoutStateForPagination).
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003877 pageLogicalHeight = fragmentedFlow.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003878
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003879 pageLogicalHeightChanged = fragmentedFlow.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003880 }
3881}
3882
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003883bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
zalan@apple.com809f4872016-12-08 18:20:01 +00003884{
3885 return willCreateColumns(desiredColumnCount);
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003886}
3887
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003888void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3889{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003890 ASSERT(!!multiColumnFlow() == requiresColumns(count));
3891 if (!multiColumnFlow())
antti@apple.com411949d2017-08-30 17:28:10 +00003892 return;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003893 multiColumnFlow()->setColumnCountAndWidth(count, width);
3894 multiColumnFlow()->setProgressionIsInline(style().hasInlineColumnAxis());
3895 multiColumnFlow()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003896}
3897
cdumez@apple.com78141732014-11-04 23:00:48 +00003898void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003899{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003900 if (!multiColumnFlow())
hyatt@apple.com86919862014-01-27 16:27:45 +00003901 return;
3902
3903 bool needsLayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003904 bool oldProgressionIsInline = multiColumnFlow()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003905 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003906 if (oldProgressionIsInline != newProgressionIsInline) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003907 multiColumnFlow()->setProgressionIsInline(newProgressionIsInline);
hyatt@apple.com86919862014-01-27 16:27:45 +00003908 needsLayout = true;
3909 }
3910
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003911 bool oldProgressionIsReversed = multiColumnFlow()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003912 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003913 if (oldProgressionIsReversed != newProgressionIsReversed) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003914 multiColumnFlow()->setProgressionIsReversed(newProgressionIsReversed);
hyatt@apple.com86919862014-01-27 16:27:45 +00003915 needsLayout = true;
3916 }
3917
3918 if (needsLayout)
3919 setNeedsLayoutAndPrefWidthsRecalc();
3920}
3921
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003922LayoutUnit RenderBlockFlow::computedColumnWidth() const
3923{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003924 if (multiColumnFlow())
3925 return multiColumnFlow()->computedColumnWidth();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003926 return contentLogicalWidth();
3927}
3928
3929unsigned RenderBlockFlow::computedColumnCount() const
3930{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003931 if (multiColumnFlow())
3932 return multiColumnFlow()->computedColumnCount();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003933
3934 return 1;
3935}
3936
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003937bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3938{
3939 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003940 if (!multiColumnFlow() || style().columnProgression() == NormalColumnProgression)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003941 return hasTopOverflow;
3942
3943 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3944 hasTopOverflow = !hasTopOverflow;
3945
3946 return hasTopOverflow;
3947}
3948
3949bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3950{
3951 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003952 if (!multiColumnFlow() || style().columnProgression() == NormalColumnProgression)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003953 return hasLeftOverflow;
3954
3955 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3956 hasLeftOverflow = !hasLeftOverflow;
3957
3958 return hasLeftOverflow;
3959}
3960
zalan@apple.comac6956c2014-09-05 14:18:06 +00003961struct InlineMinMaxIterator {
3962/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3963 inline min/max width calculations. Note the following about the way it walks:
3964 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3965 (2) We do not drill into the children of floats or replaced elements, since you can't break
3966 in the middle of such an element.
3967 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3968 distinct borders/margin/padding that contribute to the min/max width.
3969*/
3970 const RenderBlockFlow& parent;
3971 RenderObject* current;
3972 bool endOfInline;
3973 bool initial;
3974
3975 InlineMinMaxIterator(const RenderBlockFlow& p)
3976 : parent(p)
3977 , current(nullptr)
3978 , endOfInline(false)
3979 , initial(true)
3980 { }
3981
3982 RenderObject* next();
3983};
3984
3985RenderObject* InlineMinMaxIterator::next()
3986{
3987 RenderObject* result = nullptr;
3988 bool oldEndOfInline = endOfInline;
3989 endOfInline = false;
3990 do {
3991 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3992 result = current->firstChildSlow();
3993 else if (initial) {
3994 result = parent.firstChild();
3995 initial = false;
3996 }
3997
3998 if (!result) {
3999 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4000 if (!oldEndOfInline && current && current->isRenderInline()) {
4001 result = current;
4002 endOfInline = true;
4003 break;
4004 }
4005
4006 while (current && current != &parent) {
4007 result = current->nextSibling();
4008 if (result)
4009 break;
4010 current = current->parent();
4011 if (current && current != &parent && current->isRenderInline()) {
4012 result = current;
4013 endOfInline = true;
4014 break;
4015 }
4016 }
4017 }
4018
4019 if (!result)
4020 break;
4021
4022 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4023 break;
4024
4025 current = result;
4026 result = nullptr;
4027 } while (current || current == &parent);
4028 // Update our position.
4029 current = result;
4030 return result;
4031}
4032
4033static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4034{
4035 if (cssUnit.type() != Auto)
4036 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4037 return 0;
4038}
4039
4040static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4041{
4042 const RenderStyle& childStyle = child.style();
4043 if (endOfInline) {
4044 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4045 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4046 child.borderEnd();
4047 }
4048 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4049 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4050 child.borderStart();
4051}
4052
4053static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4054{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004055 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004056 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004057 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004058 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004059 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
mmaxfield@apple.com21a4dcb2016-03-13 00:36:59 +00004060 float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004061 inlineMax -= spaceWidth + font.wordSpacing();
4062 if (inlineMin > inlineMax)
4063 inlineMin = inlineMax;
4064 }
4065}
4066
4067static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4068{
4069 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4070}
4071
4072void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4073{
4074 float inlineMax = 0;
4075 float inlineMin = 0;
4076
4077 const RenderStyle& styleToUse = style();
4078 RenderBlock* containingBlock = this->containingBlock();
4079 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4080
4081 // If we are at the start of a line, we want to ignore all white-space.
4082 // Also strip spaces if we previously had text that ended in a trailing space.
4083 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004084 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004085
4086 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4087 // very specific cirucumstances (in order to match common WinIE renderings).
4088 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4089 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4090
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004091 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004092
4093 InlineMinMaxIterator childIterator(*this);
4094
4095 // Only gets added to the max preffered width once.
4096 bool addedTextIndent = false;
4097 // Signals the text indent was more negative than the min preferred width
4098 bool hasRemainingNegativeTextIndent = false;
4099
4100 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4101 RenderObject* prevFloat = 0;
4102 bool isPrevChildInlineFlow = false;
4103 bool shouldBreakLineAfterText = false;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004104 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation() & FirstHangingPunctuation;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004105 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation() & LastHangingPunctuation;
4106 RenderText* lastText = nullptr;
4107
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004108 bool addedStartPunctuationHang = false;
4109
zalan@apple.comac6956c2014-09-05 14:18:06 +00004110 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004111 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004112 child->style().autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004113 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004114 // Step One: determine whether or not we need to terminate our current line.
4115 // Each discrete chunk can become the new min-width, if it is the widest chunk
4116 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004117
4118 // Children fall into three categories:
4119 // (1) An inline flow object. These objects always have a min/max of 0,
4120 // and are included in the iteration solely so that their margins can
4121 // be added in.
4122 //
4123 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4124 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004125 // we need to break the current line, and then add in our own margins and min/max
4126 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004127 //
4128 // (3) A text object. Text runs can have breakable characters at the start,
4129 // the middle or the end. They may also lose whitespace off the front if
4130 // we're already ignoring whitespace. In order to compute accurate min-width
4131 // information, we need three pieces of information.
4132 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4133 // starts with whitespace.
4134 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4135 // ends with whitespace.
4136 // (c) the min/max width of the string (trimmed for whitespace).
4137 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004138 // If the text string starts with whitespace, then we need to terminate our current line
4139 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004140 //
4141 // If the text string has a breakable character in the middle, but didn't start
4142 // with whitespace, then we add the width of the first non-breakable run and
4143 // then end the current line. We then need to use the intermediate min/max width
4144 // values (if any of them are larger than our current min/max). We then look at
4145 // the width of the last non-breakable run and use that to start a new line
4146 // (unless we end in whitespace).
4147 const RenderStyle& childStyle = child->style();
4148 float childMin = 0;
4149 float childMax = 0;
4150
4151 if (!child->isText()) {
4152 if (child->isLineBreakOpportunity()) {
4153 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4154 inlineMin = 0;
4155 continue;
4156 }
4157 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004158 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004159 // Add in padding/border/margin from the appropriate side of
4160 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004161 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004162 childMin += bpm;
4163 childMax += bpm;
4164
4165 inlineMin += childMin;
4166 inlineMax += childMax;
4167
4168 child->setPreferredLogicalWidthsDirty(false);
4169 } else {
4170 // Inline replaced elts add in their margins to their min/max values.
hyatt@apple.com14520e42016-04-20 18:01:40 +00004171 if (!child->isFloating())
4172 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004173 LayoutUnit margins = 0;
4174 Length startMargin = childStyle.marginStart();
4175 Length endMargin = childStyle.marginEnd();
4176 if (startMargin.isFixed())
4177 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4178 if (endMargin.isFixed())
4179 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4180 childMin += margins.ceilToFloat();
4181 childMax += margins.ceilToFloat();
4182 }
4183 }
4184
cdumez@apple.comf8022152014-10-15 00:29:51 +00004185 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004186 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004187 // Terminate the current line as far as minwidth is concerned.
hyatt@apple.com247170f2017-02-28 16:23:15 +00004188 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4189 computeChildPreferredLogicalWidths(*child, childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth);
4190 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4191 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004192
4193 bool clearPreviousFloat;
4194 if (child->isFloating()) {
4195 clearPreviousFloat = (prevFloat
4196 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4197 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4198 prevFloat = child;
4199 } else
4200 clearPreviousFloat = false;
4201
4202 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
antti@apple.comae85e112017-08-31 23:27:02 +00004203 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004204 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4205 inlineMin = 0;
4206 }
4207
4208 // If we're supposed to clear the previous float, then terminate maxwidth as well.
antti@apple.comae85e112017-08-31 23:27:02 +00004209 if (clearPreviousFloat) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004210 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4211 inlineMax = 0;
4212 }
4213
4214 // Add in text-indent. This is added in only once.
antti@apple.comae85e112017-08-31 23:27:02 +00004215 if (!addedTextIndent && !child->isFloating()) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004216 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4217 childMin += ceiledIndent;
4218 childMax += ceiledIndent;
4219
4220 if (childMin < 0)
4221 textIndent = LayoutUnit::fromFloatCeil(childMin);
4222 else
4223 addedTextIndent = true;
4224 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004225
antti@apple.comae85e112017-08-31 23:27:02 +00004226 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating())
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004227 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004228
4229 // Add our width to the max.
4230 inlineMax += std::max<float>(0, childMax);
4231
antti@apple.comae85e112017-08-31 23:27:02 +00004232 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText))) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004233 if (child->isFloating())
4234 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4235 else
4236 inlineMin += childMin;
4237 } else {
4238 // Now check our line.
4239 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4240
4241 // Now start a new line.
antti@apple.comae85e112017-08-31 23:27:02 +00004242 inlineMin = 0;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004243 }
4244
4245 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4246 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4247 inlineMin = 0;
4248 }
4249
4250 // We are no longer stripping whitespace at the start of a line.
4251 if (!child->isFloating()) {
4252 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004253 trailingSpaceChild = nullptr;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004254 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004255 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004256 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004257 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004258 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004259
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004260 if (renderText.style().hasTextCombine() && renderText.isCombineText())
zalan@apple.com6cad78f2017-09-19 20:28:29 +00004261 downcast<RenderCombineText>(renderText).combineTextIfNeeded();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004262
4263 // Determine if we have a breakable character. Pass in
4264 // whether or not we should ignore any spaces at the front
4265 // of the string. If those are going to be stripped out,
4266 // then they shouldn't be considered in the breakable char
4267 // check.
4268 bool hasBreakableChar, hasBreak;
4269 float beginMin, endMin;
4270 bool beginWS, endWS;
4271 float beginMax, endMax;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004272 bool strippingBeginWS = stripFrontSpaces;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004273 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004274 hasBreakableChar, hasBreak, beginMax, endMax,
4275 childMin, childMax, stripFrontSpaces);
4276
4277 // This text object will not be rendered, but it may still provide a breaking opportunity.
4278 if (!hasBreak && !childMax) {
4279 if (autoWrap && (beginWS || endWS)) {
4280 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4281 inlineMin = 0;
4282 }
4283 continue;
4284 }
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004285
4286 lastText = &renderText;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004287
4288 if (stripFrontSpaces)
4289 trailingSpaceChild = child;
4290 else
4291 trailingSpaceChild = 0;
4292
4293 // Add in text-indent. This is added in only once.
4294 float ti = 0;
4295 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4296 ti = textIndent.ceilToFloat();
4297 childMin += ti;
4298 beginMin += ti;
4299
4300 // It the text indent negative and larger than the child minimum, we re-use the remainder
4301 // in future minimum calculations, but using the negative value again on the maximum
4302 // will lead to under-counting the max pref width.
4303 if (!addedTextIndent) {
4304 childMax += ti;
4305 beginMax += ti;
4306 addedTextIndent = true;
4307 }
4308
4309 if (childMin < 0) {
4310 textIndent = childMin;
4311 hasRemainingNegativeTextIndent = true;
4312 }
4313 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004314
4315 // See if we have a hanging punctuation situation at the start.
4316 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004317 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4318 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004319 childMin -= hangStartWidth;
4320 beginMin -= hangStartWidth;
4321 childMax -= hangStartWidth;
4322 beginMax -= hangStartWidth;
4323 addedStartPunctuationHang = true;
4324 }
4325
zalan@apple.comac6956c2014-09-05 14:18:06 +00004326 // If we have no breakable characters at all,
4327 // then this is the easy case. We add ourselves to the current
4328 // min and max and continue.
4329 if (!hasBreakableChar)
4330 inlineMin += childMin;
4331 else {
4332 // We have a breakable character. Now we need to know if
4333 // we start and end with whitespace.
4334 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004335 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004336 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4337 } else {
4338 inlineMin += beginMin;
4339 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4340 childMin -= ti;
4341 }
4342
4343 inlineMin = childMin;
4344
4345 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004346 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004347 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4348 inlineMin = 0;
4349 shouldBreakLineAfterText = false;
4350 } else {
4351 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4352 inlineMin = endMin;
4353 shouldBreakLineAfterText = true;
4354 }
4355 }
4356
4357 if (hasBreak) {
4358 inlineMax += beginMax;
4359 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4360 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4361 inlineMax = endMax;
4362 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004363 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004364 } else
4365 inlineMax += std::max<float>(0, childMax);
4366 }
4367
antti@apple.comae85e112017-08-31 23:27:02 +00004368 // Ignore spaces after a list marker.
4369 if (child->isListMarker())
zalan@apple.comac6956c2014-09-05 14:18:06 +00004370 stripFrontSpaces = true;
4371 } else {
4372 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4373 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4374 inlineMin = inlineMax = 0;
4375 stripFrontSpaces = true;
4376 trailingSpaceChild = 0;
4377 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004378 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004379 }
4380
4381 if (!child->isText() && child->isRenderInline())
4382 isPrevChildInlineFlow = true;
4383 else
4384 isPrevChildInlineFlow = false;
4385
4386 oldAutoWrap = autoWrap;
4387 }
4388
4389 if (styleToUse.collapseWhiteSpace())
4390 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004391
4392 if (canHangPunctuationAtEnd && lastText && lastText->textLength() > 0) {
4393 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->textLength() - 1;
4394 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4395 inlineMin -= endHangWidth;
4396 inlineMax -= endHangWidth;
4397 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004398
4399 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4400 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4401}
4402
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004403}
4404// namespace WebCore