blob: 1b1359549c69542a0a6ec22ccba0190b24e86a9d [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
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +0000555 if (view().layoutState()->m_pageLogicalHeight)
556 setPageLogicalOffset(view().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.
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +0000615 if (view().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
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +0000693 LayoutSize oldLayoutDelta = view().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
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +0000741 bool paginated = view().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()) {
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +0000791 view().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
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +0000814 ASSERT(view().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.
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001112 LayoutState* layoutState = view().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.
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001287 LayoutState* layoutState = view().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();
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001498 bool checkPageBreaks = !checkColumnBreaks && view().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();
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001523 bool checkPageBreaks = !checkColumnBreaks && view().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{
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001810 ASSERT(view().layoutState() && view().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.
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001909 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001910 if (!pageLogicalHeight)
1911 return 0;
1912
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001913 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1914 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001915
1916 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001917 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1918 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001919 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001920 return firstPageLogicalTop + fragmentedFlow->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001921}
1922
1923LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1924{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001925 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1926 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001927 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001928 if (!pageLogicalHeight)
1929 return 0;
1930
1931 // Now check for a flow thread.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001932 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1933 if (!fragmentedFlow)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001934 return pageLogicalHeight;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001935 return fragmentedFlow->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
weinig@apple.com31324fd2013-10-28 19:22:51 +00001936}
1937
1938LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1939{
1940 offset += offsetFromLogicalTopOfFirstPage();
1941
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001942 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1943 if (!fragmentedFlow) {
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00001944 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001945 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1946 if (pageBoundaryRule == IncludePageBoundary) {
1947 // If includeBoundaryPoint is true the line exactly on the top edge of a
1948 // column will act as being part of the previous column.
1949 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1950 }
1951 return remainingHeight;
1952 }
1953
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001954 return fragmentedFlow->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001955}
1956
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001957LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1958{
antti@apple.comeae76122017-09-20 15:37:23 +00001959 return logicalHeightForChild(child);
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001960}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001961
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001962void RenderBlockFlow::layoutLineGridBox()
1963{
akling@apple.com827be9c2013-10-29 02:58:43 +00001964 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001965 setLineGridBox(0);
1966 return;
1967 }
1968
1969 setLineGridBox(0);
1970
akling@apple.com1aa97b02013-10-31 21:59:49 +00001971 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001972 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1973 lineGridBox->setConstructed();
1974 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1975 VerticalPositionCache verticalPositionCache;
1976 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1977
aestes@apple.com13aae082016-01-02 08:03:08 +00001978 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001979
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001980 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1981 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1982 // to this grid.
1983}
1984
weinig@apple.com12840dc2013-10-22 23:59:08 +00001985bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001986{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001987 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001988}
1989
1990void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1991{
1992 RenderBlock::styleDidChange(diff, oldStyle);
1993
1994 // After our style changed, if we lose our ability to propagate floats into next sibling
1995 // blocks, then we need to find the top most parent containing that overhanging float and
1996 // then mark its descendants with floats for layout and clear all floats from its next
1997 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1998 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1999 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2000 RenderBlockFlow* parentBlock = this;
2001 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002002
weinig@apple.comc77041e2013-12-14 18:05:45 +00002003 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2004 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00002005 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00002006 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002007 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2008 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002009 if (ancestor.hasOverhangingFloat(renderer)) {
2010 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002011 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002012 }
2013 }
2014 }
2015 }
2016
2017 parentBlock->markAllDescendantsWithFloatsForLayout();
2018 parentBlock->markSiblingsWithFloatsForLayout();
2019 }
zalan@apple.com07a1ebc2017-03-16 01:56:57 +00002020 // Fresh floats need to be reparented if they actually belong to the previous anonymous block.
2021 // It copies the logic of RenderBlock::addChildIgnoringContinuation
2022 if (noLongerAffectsParentBlock() && style().isFloating() && previousSibling() && previousSibling()->isAnonymousBlock())
2023 downcast<RenderBoxModelObject>(*parent()).moveChildTo(&downcast<RenderBoxModelObject>(*previousSibling()), this);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002024
antti@apple.com9e891c82014-05-22 06:12:34 +00002025 if (diff >= StyleDifferenceRepaint) {
2026 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2027 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2028 invalidateLineLayoutPath();
2029 }
2030
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002031 if (multiColumnFlow())
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002032 updateStylesForColumnChildren();
2033}
2034
2035void RenderBlockFlow::updateStylesForColumnChildren()
2036{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002037 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFragmentedFlow() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
antti@apple.com454418f2016-04-25 19:49:23 +00002038 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002039}
2040
akling@apple.combdae43242013-10-25 12:00:20 +00002041void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002042{
akling@apple.com827be9c2013-10-29 02:58:43 +00002043 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002044 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2045
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002046 if (oldStyle) {
2047 EPosition oldPosition = oldStyle->position();
2048 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002049
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002050 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2051 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2052 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002053 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002054 }
2055
2056 RenderBlock::styleWillChange(diff, newStyle);
2057}
2058
antti@apple.coma2c7f242013-10-22 22:37:25 +00002059void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002060{
2061 if (containsFloats())
2062 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002063
antti@apple.comfea51992013-10-28 13:39:23 +00002064 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002065 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002066 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002067 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002068 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002069
antti@apple.coma2c7f242013-10-22 22:37:25 +00002070 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002071}
2072
zalan@apple.com232b0932016-12-24 18:00:00 +00002073void RenderBlockFlow::addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002074{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002075 // When a portion of the render tree is being detached, anonymous blocks
2076 // will be combined as their children are deleted. In this process, the
2077 // anonymous block later in the tree is merged into the one preceeding it.
2078 // It can happen that the later block (this) contains floats that the
2079 // previous block (toBlockFlow) did not contain, and thus are not in the
2080 // floating objects list for toBlockFlow. This can result in toBlockFlow
2081 // containing floats that are not in it's floating objects list, but are in
2082 // the floating objects lists of siblings and parents. This can cause
2083 // problems when the float itself is deleted, since the deletion code
2084 // assumes that if a float is not in it's containing block's floating
2085 // objects list, it isn't in any floating objects list. In order to
2086 // preserve this condition (removing it has serious performance
2087 // implications), we need to copy the floating objects from the old block
2088 // (this) to the new block (toBlockFlow). The float's metrics will likely
2089 // all be wrong, but since toBlockFlow is already marked for layout, this
2090 // will get fixed before anything gets displayed.
2091 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
zalan@apple.com232b0932016-12-24 18:00:00 +00002092 if (!m_floatingObjects)
2093 return;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002094
zalan@apple.com232b0932016-12-24 18:00:00 +00002095 if (!toBlockFlow.m_floatingObjects)
2096 toBlockFlow.createFloatingObjects();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002097
zalan@apple.com26018542017-03-30 01:25:00 +00002098 for (auto& floatingObject : m_floatingObjects->set()) {
2099 if (toBlockFlow.containsFloat(floatingObject->renderer()))
2100 continue;
zalan@apple.com232b0932016-12-24 18:00:00 +00002101 toBlockFlow.m_floatingObjects->add(floatingObject->cloneForNewParent());
zalan@apple.com26018542017-03-30 01:25:00 +00002102 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002103}
2104
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002105void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002106{
zalan@apple.com232b0932016-12-24 18:00:00 +00002107 auto& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002108 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
zalan@apple.com232b0932016-12-24 18:00:00 +00002109 addFloatsToNewParent(toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002110}
2111
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002112void RenderBlockFlow::addOverflowFromFloats()
2113{
2114 if (!m_floatingObjects)
2115 return;
2116
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002117 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2118 auto end = floatingObjectSet.end();
2119 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002120 const auto& floatingObject = *it->get();
2121 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002122 addOverflowFromChild(&floatingObject.renderer(), floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002123 }
2124}
2125
2126void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2127{
2128 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2129
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002130 if (!multiColumnFlow() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002131 addOverflowFromFloats();
2132}
2133
2134void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2135{
2136 // Repaint any overhanging floats (if we know we're the one to paint them).
2137 // Otherwise, bail out.
2138 if (!hasOverhangingFloats())
2139 return;
2140
2141 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2142 // in this block. Better yet would be to push extra state for the containers of other floats.
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00002143 LayoutStateDisabler layoutStateDisabler(view());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002144 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2145 auto end = floatingObjectSet.end();
2146 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002147 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002148 // Only repaint the object if it is overhanging, is not in its own layer, and
2149 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2150 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002151 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002152 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002153 && !renderer.hasSelfPaintingLayer()
2154 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2155 renderer.repaint();
2156 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002157 }
2158 }
2159}
2160
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002161void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002162{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002163 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002164
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002165 if (!multiColumnFlow() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002166 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002167
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002168 // Iterate over our children and paint the column rules as needed.
2169 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2170 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2171 columnSet.paintColumnRules(paintInfo, childPoint);
2172 }
2173}
2174
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002175void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2176{
2177 if (!m_floatingObjects)
2178 return;
2179
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002180 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2181 auto end = floatingObjectSet.end();
2182 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002183 const auto& floatingObject = *it->get();
2184 auto& renderer = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002185 // Only paint the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002186 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002187 PaintInfo currentPaintInfo(paintInfo);
2188 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002189 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, paintOffset + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002190 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002191 if (!preservePhase) {
2192 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002193 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002194 currentPaintInfo.phase = PaintPhaseFloat;
zalan@apple.com6816b132015-10-17 19:14:53 +00002195 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002196 currentPaintInfo.phase = PaintPhaseForeground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002197 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002198 currentPaintInfo.phase = PaintPhaseOutline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002199 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002200 }
2201 }
2202 }
2203}
2204
weinig@apple.com12840dc2013-10-22 23:59:08 +00002205void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002206{
2207 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002208 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2209 auto end = floatingObjectSet.end();
2210 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002211 const auto& floatingObject = *it->get();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002212 LayoutRect floatBox(offsetFromRootBlock.width(), offsetFromRootBlock.height(), floatingObject.renderer().width(), floatingObject.renderer().height());
2213 floatBox.move(floatingObject.locationOffsetOfBorderBox());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002214 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002215 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002216 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002217 }
2218 }
2219}
2220
2221void RenderBlockFlow::createFloatingObjects()
2222{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002223 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002224}
2225
2226void RenderBlockFlow::removeFloatingObjects()
2227{
2228 if (!m_floatingObjects)
2229 return;
2230
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002231 markSiblingsWithFloatsForLayout();
2232
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002233 m_floatingObjects->clear();
2234}
2235
weinig@apple.com12840dc2013-10-22 23:59:08 +00002236FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002237{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002238 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002239
2240 // Create the list of special objects if we don't aleady have one
2241 if (!m_floatingObjects)
2242 createFloatingObjects();
2243 else {
2244 // Don't insert the floatingObject again if it's already in the list
2245 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002246 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002247 if (it != floatingObjectSet.end())
2248 return it->get();
2249 }
2250
2251 // Create the special floatingObject entry & append it to the list
2252
weinig@apple.com12840dc2013-10-22 23:59:08 +00002253 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002254
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002255 // 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 +00002256 bool isChildRenderBlock = floatBox.isRenderBlock();
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00002257 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002258 floatBox.setChildNeedsLayout(MarkOnlyThis);
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00002259
2260 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002261 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2262 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002263 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002264 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2265 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002266 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002267 floatBox.updateLogicalWidth();
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00002268 floatBox.computeAndSetBlockDirectionMargins(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002269 }
2270
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002271 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002272
aestes@apple.com13aae082016-01-02 08:03:08 +00002273 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002274}
2275
weinig@apple.com12840dc2013-10-22 23:59:08 +00002276void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002277{
2278 if (m_floatingObjects) {
2279 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002280 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002281 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002282 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002283 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002284 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2285 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002286
2287 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2288 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2289 logicalBottom = LayoutUnit::max();
2290 else {
2291 // Special-case zero- and less-than-zero-height floats: those don't touch
2292 // the line that they're on, but it still needs to be dirtied. This is
2293 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002294 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002295 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002296 if (floatingObject.originatingLine()) {
2297 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002298 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002299 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2300 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002301 }
2302#if !ASSERT_DISABLED
zalan@apple.comd2acead2017-09-20 22:03:06 +00002303 floatingObject.clearOriginatingLine();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002304#endif
2305 }
2306 markLinesDirtyInBlockRange(0, logicalBottom);
2307 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002308 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002309 }
2310 }
2311}
2312
2313void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2314{
2315 if (!containsFloats())
2316 return;
2317
2318 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2319 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002320 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002321 m_floatingObjects->remove(curr);
2322 if (floatingObjectSet.isEmpty())
2323 break;
2324 curr = floatingObjectSet.last().get();
2325 }
2326}
2327
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002328LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2329{
2330 LayoutUnit offset = fixedOffset;
2331 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2332 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2333 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2334}
2335
2336LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2337{
2338 LayoutUnit offset = fixedOffset;
2339 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2340 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2341 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2342}
2343
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002344void RenderBlockFlow::computeLogicalLocationForFloat(FloatingObject& floatingObject, LayoutUnit& logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002345{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002346 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002347 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002348 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002349
andersca@apple.com86298632013-11-10 19:32:33 +00002350 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002351
2352 LayoutUnit floatLogicalLeft;
2353
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002354 bool insideFragmentedFlow = enclosingFragmentedFlow();
hyatt@apple.com87515262014-09-04 21:20:12 +00002355 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2356
2357 if (isInitialLetter) {
2358 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2359 if (letterClearance > 0) {
2360 logicalTopOffset += letterClearance;
2361 setLogicalHeight(logicalHeight() + letterClearance);
2362 }
2363 }
2364
akling@apple.com827be9c2013-10-29 02:58:43 +00002365 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002366 LayoutUnit heightRemainingLeft = 1;
2367 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002368 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2369 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002370 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002371 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002372 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002373 // Have to re-evaluate all of our offsets, since they may have changed.
2374 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2375 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002376 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002377 }
2378 }
andersca@apple.com86298632013-11-10 19:32:33 +00002379 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002380 } else {
2381 LayoutUnit heightRemainingLeft = 1;
2382 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002383 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2384 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002385 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002386 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002387 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002388 // Have to re-evaluate all of our offsets, since they may have changed.
2389 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2390 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002391 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002392 }
2393 }
2394 // Use the original width of the float here, since the local variable
2395 // |floatLogicalWidth| was capped to the available line width. See
2396 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002397 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002398 }
2399
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002400 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
2401 LayoutUnit childBeforeMargin = marginBeforeForChild(childBox);
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002402
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002403 if (isInitialLetter)
2404 adjustInitialLetterPosition(childBox, logicalTopOffset, childBeforeMargin);
2405
2406 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
2407 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
2408
2409 setLogicalTopForFloat(floatingObject, logicalTopOffset);
2410 setLogicalTopForChild(childBox, logicalTopOffset + childBeforeMargin);
2411
2412 setLogicalMarginsForFloat(floatingObject, childLogicalLeftMargin, childBeforeMargin);
2413}
2414
2415void RenderBlockFlow::adjustInitialLetterPosition(RenderBox& childBox, LayoutUnit& logicalTopOffset, LayoutUnit& marginBeforeOffset)
2416{
2417 const RenderStyle& style = firstLineStyle();
2418 const FontMetrics& fontMetrics = style.fontMetrics();
2419 if (!fontMetrics.hasCapHeight())
2420 return;
2421
2422 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2423 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2424
2425 // Make an adjustment to align with the cap height of a theoretical block line.
2426 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2427 logicalTopOffset += adjustment;
2428
2429 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2430 // positive for raised and negative for sunken).
2431 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2432
2433 // 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.
2434 if (dropHeightDelta < 0)
2435 marginBeforeOffset += -dropHeightDelta * heightOfLine;
2436
2437 // 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
2438 // empty lines beside the first letter.
2439 if (dropHeightDelta > 0)
2440 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002441}
2442
2443bool RenderBlockFlow::positionNewFloats()
2444{
2445 if (!m_floatingObjects)
2446 return false;
2447
2448 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2449 if (floatingObjectSet.isEmpty())
2450 return false;
2451
2452 // If all floats have already been positioned, then we have no work to do.
2453 if (floatingObjectSet.last()->isPlaced())
2454 return false;
2455
2456 // Move backwards through our floating object list until we find a float that has
2457 // already been positioned. Then we'll be able to move forward, positioning all of
2458 // the new floats that need it.
2459 auto it = floatingObjectSet.end();
2460 --it; // Go to last item.
2461 auto begin = floatingObjectSet.begin();
2462 FloatingObject* lastPlacedFloatingObject = 0;
2463 while (it != begin) {
2464 --it;
2465 if ((*it)->isPlaced()) {
2466 lastPlacedFloatingObject = it->get();
2467 ++it;
2468 break;
2469 }
2470 }
2471
2472 LayoutUnit logicalTop = logicalHeight();
2473
2474 // The float cannot start above the top position of the last positioned float.
2475 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002476 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002477
2478 auto end = floatingObjectSet.end();
2479 // Now walk through the set of unpositioned floats and place them.
2480 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002481 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002482 // The containing block is responsible for positioning floats, so if we have floats in our
2483 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002484 auto& childBox = floatingObject.renderer();
2485 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002486 continue;
2487
weinig@apple.com12840dc2013-10-22 23:59:08 +00002488 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002489
akling@apple.com827be9c2013-10-29 02:58:43 +00002490 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002491 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002492 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002493 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002494
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002495 computeLogicalLocationForFloat(floatingObject, logicalTop);
2496 LayoutUnit childLogicalTop = logicalTopForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002497
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002498 estimateFragmentRangeForBoxChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002499
hyatt@apple.comccad3742015-02-04 21:39:00 +00002500 childBox.markForPaginationRelayoutIfNeeded();
2501 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002502
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00002503 LayoutState* layoutState = view().layoutState();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002504 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002505 if (isPaginated) {
2506 // If we are unsplittable and don't fit, then we need to move down.
2507 // We include our margins as part of the unsplittable area.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002508 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, childLogicalTop - logicalTop, marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002509
2510 // See if we have a pagination strut that is making us move down further.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002511 // Note that an unsplittable child can't also have a pagination strut, so this
2512 // is exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002513 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002514 if (childBlock && childBlock->paginationStrut()) {
2515 newLogicalTop += childBlock->paginationStrut();
2516 childBlock->setPaginationStrut(0);
2517 }
2518
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002519 if (newLogicalTop != logicalTop) {
2520 floatingObject.setPaginationStrut(newLogicalTop - logicalTop);
2521 computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002522 if (childBlock)
2523 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002524 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002525 logicalTop = newLogicalTop;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002526 }
2527
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002528 if (updateFragmentRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002529 childBox.setNeedsLayout(MarkOnlyThis);
2530 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002531 }
2532 }
2533
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002534 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + (logicalTopForChild(childBox) - logicalTop) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002535
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002536 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002537
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002538 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002539 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002540 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002541 if (childBox.checkForRepaintDuringLayout())
2542 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002543 }
2544 return true;
2545}
2546
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002547void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002548{
2549 positionNewFloats();
2550 // set y position
2551 LayoutUnit newY = 0;
2552 switch (clear) {
2553 case CLEFT:
2554 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2555 break;
2556 case CRIGHT:
2557 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2558 break;
2559 case CBOTH:
2560 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002561 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002562 default:
2563 break;
2564 }
2565 if (height() < newY)
2566 setLogicalHeight(newY);
2567}
2568
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002569LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002570{
2571 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002572 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002573
2574 return fixedOffset;
2575}
2576
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002577LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002578{
2579 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002580 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002581
2582 return fixedOffset;
2583}
2584
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002585LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002586{
2587 if (!m_floatingObjects)
2588 return logicalHeight;
2589
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002590 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2591}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002592
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002593LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2594{
2595 if (!m_floatingObjects)
2596 return logicalHeight;
2597
2598 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002599}
2600
2601LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2602{
2603 if (!m_floatingObjects)
2604 return 0;
2605 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002606 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2607 auto end = floatingObjectSet.end();
2608 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002609 const auto& floatingObject = *it->get();
2610 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002611 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002612 }
2613 return lowestFloatBottom;
2614}
2615
hyatt@apple.com87515262014-09-04 21:20:12 +00002616LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2617{
2618 if (!m_floatingObjects)
2619 return 0;
2620 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002621 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2622 auto end = floatingObjectSet.end();
2623 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002624 const auto& floatingObject = *it->get();
2625 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == FIRST_LETTER && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002626 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002627 }
2628 return lowestFloatBottom;
2629}
2630
weinig@apple.com12840dc2013-10-22 23:59:08 +00002631LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002632{
2633 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002634 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002635 return 0;
2636
weinig@apple.com12840dc2013-10-22 23:59:08 +00002637 LayoutUnit childLogicalTop = child.logicalTop();
2638 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002639 LayoutUnit lowestFloatLogicalBottom = 0;
2640
2641 // Floats that will remain the child's responsibility to paint should factor into its
2642 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002643 auto childEnd = child.m_floatingObjects->set().end();
2644 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002645 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002646 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002647 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002648 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002649
2650 if (logicalBottom > logicalHeight()) {
2651 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002652 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002653 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2654 bool shouldPaint = false;
2655
2656 // The nearest enclosing layer always paints the float (so that zindex and stacking
2657 // behaves properly). We always want to propagate the desire to paint the float as
2658 // far out as we can, to the outermost block that overlaps the float, stopping only
2659 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002660 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2661 floatingObject.setShouldPaint(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002662 shouldPaint = true;
2663 }
2664 // We create the floating object list lazily.
2665 if (!m_floatingObjects)
2666 createFloatingObjects();
2667
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002668 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002669 }
2670 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002671 const auto& renderer = floatingObject.renderer();
2672 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2673 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002674 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2675 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2676 // layer.
2677 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2678 // it should paint.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002679 floatingObject.setShouldPaint(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002680 }
2681
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002682 // 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 +00002683 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002684 child.addOverflowFromChild(&renderer, floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002685 }
2686 }
2687 return lowestFloatLogicalBottom;
2688}
2689
weinig@apple.com12840dc2013-10-22 23:59:08 +00002690bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002691{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002692 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002693 return false;
2694
2695 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002696 const auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002697 if (it == floatingObjectSet.end())
2698 return false;
2699
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002700 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002701}
2702
hyatt@apple.com21c60802015-04-01 18:10:32 +00002703void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002704{
2705 ASSERT(!avoidsFloats());
2706
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002707 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2708 if (createsNewFormattingContext())
2709 return;
2710
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002711 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2712 if (!prev->m_floatingObjects)
2713 return;
2714
2715 logicalLeftOffset += marginLogicalLeft();
2716
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002717 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2718 auto prevEnd = prevSet.end();
2719 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002720 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002721 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002722 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002723 // We create the floating object list lazily.
2724 if (!m_floatingObjects)
2725 createFloatingObjects();
2726
2727 // Applying the child's margin makes no sense in the case where the child was passed in.
2728 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2729 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2730 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2731 // will get applied twice.
2732 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002733 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2734 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002735
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002736 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002737 }
2738 }
2739 }
2740}
2741
2742void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2743{
2744 if (!everHadLayout() && !containsFloats())
2745 return;
2746
2747 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2748 setChildNeedsLayout(markParents);
2749
2750 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002751 removeFloatingObject(*floatToRemove);
hyatt@apple.com11a5e5c2016-05-19 21:51:31 +00002752 else if (childrenInline())
hyatt@apple.com00e93142016-05-18 18:59:40 +00002753 return;
2754
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002755 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002756 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2757 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2758 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002759 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002760 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2761 block.setChildNeedsLayout(markParents);
2762 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002763 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002764 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002765 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2766 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002767 }
2768}
2769
2770void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2771{
2772 if (!m_floatingObjects)
2773 return;
2774
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002775 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2776 auto end = floatingObjectSet.end();
2777
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002778 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002779 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002780 continue;
2781
cdumez@apple.come9437792014-10-08 23:33:43 +00002782 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002783 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2784 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002785 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002786 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002787 if (nextBlock.containsFloat(floatingBox))
2788 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002789 }
2790 }
2791}
2792
zalan@apple.com6816b132015-10-17 19:14:53 +00002793LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002794{
akling@apple.com827be9c2013-10-29 02:58:43 +00002795 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002796 return point;
2797
2798 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2799 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2800 // case.
2801 if (isHorizontalWritingMode())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002802 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * child.locationOffsetOfBorderBox().height());
2803 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * child.locationOffsetOfBorderBox().width(), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002804}
2805
weinig@apple.com12840dc2013-10-22 23:59:08 +00002806LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002807{
2808 // There is no need to compute clearance if we have no floats.
2809 if (!containsFloats())
2810 return 0;
2811
2812 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002813 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002814 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002815 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002816 case CNONE:
2817 break;
2818 case CLEFT:
2819 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2820 break;
2821 case CRIGHT:
2822 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2823 break;
2824 case CBOTH:
2825 logicalBottom = lowestFloatLogicalBottom();
2826 break;
2827 }
2828
2829 // 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 +00002830 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002831 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002832 LayoutUnit newLogicalTop = logicalTop;
2833 while (true) {
zalan@apple.com64761fe2016-03-02 21:42:22 +00002834 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002835 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2836 return newLogicalTop - logicalTop;
2837
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002838 RenderFragmentContainer* fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2839 LayoutRect borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002840 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2841
2842 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002843 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2844 LayoutUnit childOldMarginLeft = child.marginLeft();
2845 LayoutUnit childOldMarginRight = child.marginRight();
2846 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002847
weinig@apple.com12840dc2013-10-22 23:59:08 +00002848 child.setLogicalTop(newLogicalTop);
2849 child.updateLogicalWidth();
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002850 fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2851 borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002852 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2853
weinig@apple.com12840dc2013-10-22 23:59:08 +00002854 child.setLogicalTop(childOldLogicalTop);
2855 child.setLogicalWidth(childOldLogicalWidth);
2856 child.setMarginLeft(childOldMarginLeft);
2857 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002858
2859 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2860 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2861 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2862 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2863 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002864 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002865 return newLogicalTop - logicalTop;
2866 }
2867
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002868 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002869 ASSERT(newLogicalTop >= logicalTop);
2870 if (newLogicalTop < logicalTop)
2871 break;
2872 }
2873 ASSERT_NOT_REACHED();
2874 }
2875 return result;
2876}
2877
2878bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2879{
2880 if (!m_floatingObjects)
2881 return false;
2882
2883 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002884 if (is<RenderView>(*this))
2885 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002886
2887 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2888 auto begin = floatingObjectSet.begin();
2889 for (auto it = floatingObjectSet.end(); it != begin;) {
2890 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002891 const auto& floatingObject = *it->get();
2892 auto& renderer = floatingObject.renderer();
2893 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002894 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002895 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002896 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2897 return true;
2898 }
2899 }
2900 }
2901
2902 return false;
2903}
2904
weinig@apple.com611b9292013-10-20 22:57:54 +00002905bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2906{
2907 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002908
darin@apple.come1be6ca2014-04-28 04:19:10 +00002909 if (auto simpleLineLayout = this->simpleLineLayout())
2910 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002911
weinig@apple.com611b9292013-10-20 22:57:54 +00002912 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2913}
2914
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002915void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2916{
akling@apple.com827be9c2013-10-29 02:58:43 +00002917 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002918 return;
2919
2920 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2921 // for either overflow or translations via relative positioning.
2922 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002923 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2924
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002925 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002926 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002927 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002928 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002929 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002930 }
2931 } else {
2932 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2933 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002934 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2935 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002936 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002937 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002938 left = std::min(left, x + obj->x());
2939 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002940 }
2941 }
2942 }
2943 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002944
2945 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002946 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2947 auto end = floatingObjectSet.end();
2948 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002949 const auto& floatingObject = *it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002950 // Only examine the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002951 if (floatingObject.shouldPaint()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002952 LayoutUnit floatLeft = floatingObject.translationOffsetToAncestor().width();
zalan@apple.com6816b132015-10-17 19:14:53 +00002953 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002954 left = std::min(left, floatLeft);
2955 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002956 }
2957 }
2958 }
2959}
2960
2961void RenderBlockFlow::fitBorderToLinesIfNeeded()
2962{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002963 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002964 return;
2965
2966 // Walk any normal flow lines to snugly fit.
2967 LayoutUnit left = LayoutUnit::max();
2968 LayoutUnit right = LayoutUnit::min();
2969 LayoutUnit oldWidth = contentWidth();
2970 adjustForBorderFit(0, left, right);
2971
2972 // Clamp to our existing edges. We can never grow. We only shrink.
2973 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2974 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002975 left = std::min(rightEdge, std::max(leftEdge, left));
2976 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002977
2978 LayoutUnit newContentWidth = right - left;
2979 if (newContentWidth == oldWidth)
2980 return;
2981
2982 setOverrideLogicalContentWidth(newContentWidth);
2983 layoutBlock(false);
2984 clearOverrideLogicalContentWidth();
2985}
2986
2987void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2988{
2989 if (logicalTop >= logicalBottom)
2990 return;
2991
antti@apple.combe9d3e12014-05-11 09:42:47 +00002992 // Floats currently affect the choice whether to use simple line layout path.
2993 if (m_simpleLineLayout) {
2994 invalidateLineLayoutPath();
2995 return;
2996 }
2997
weinig@apple.com611b9292013-10-20 22:57:54 +00002998 RootInlineBox* lowestDirtyLine = lastRootBox();
2999 RootInlineBox* afterLowest = lowestDirtyLine;
3000 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3001 afterLowest = lowestDirtyLine;
3002 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3003 }
3004
3005 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3006 afterLowest->markDirty();
3007 afterLowest = afterLowest->prevRootBox();
3008 }
3009}
3010
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003011std::optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003012{
3013 if (isWritingModeRoot() && !isRubyRun())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003014 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003015
3016 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003017 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003018
antti@apple.com940f5872013-10-24 20:31:11 +00003019 if (!hasLines())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003020 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003021
darin@apple.come1be6ca2014-04-28 04:19:10 +00003022 if (auto simpleLineLayout = this->simpleLineLayout())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003023 return std::optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003024
akling@apple.comee3c8df2013-11-06 08:09:44 +00003025 ASSERT(firstRootBox());
3026 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003027}
3028
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003029std::optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003030{
3031 if (isWritingModeRoot() && !isRubyRun())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003032 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003033
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003034 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3035 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3036 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003037 if (!childrenInline()) {
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003038 std::optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003039 if (!inlineBlockBaseline)
3040 return inlineBlockBaseline;
3041 lastBaseline = inlineBlockBaseline.value();
3042 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003043 if (!hasLines()) {
3044 if (!hasLineIfEmpty())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003045 return std::optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003046 const auto& fontMetrics = firstLineStyle().fontMetrics();
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003047 return std::optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003048 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003049 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003050 }
3051
3052 if (auto simpleLineLayout = this->simpleLineLayout())
3053 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3054 else {
3055 bool isFirstLine = lastRootBox() == firstRootBox();
3056 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3057 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3058 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003059 }
3060 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3061 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3062 // enough with the spec to not cause tons of breakages).
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003063 return std::optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003064}
3065
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003066void RenderBlockFlow::setSelectionState(SelectionState state)
3067{
3068 if (state != SelectionNone)
3069 ensureLineBoxes();
3070 RenderBoxModelObject::setSelectionState(state);
3071}
3072
weinig@apple.com12840dc2013-10-22 23:59:08 +00003073GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003074 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3075{
antti@apple.comfea51992013-10-28 13:39:23 +00003076 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003077
weinig@apple.com611b9292013-10-20 22:57:54 +00003078 GapRects result;
3079
3080 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3081
antti@apple.com0e632aa2013-10-22 21:03:38 +00003082 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003083 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003084 // 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 +00003085 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3086 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3087 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3088 }
3089 return result;
3090 }
3091
3092 RootInlineBox* lastSelectedLine = 0;
3093 RootInlineBox* curr;
3094 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3095
3096 // Now paint the gaps for the lines.
3097 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3098 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3099 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3100
3101 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003102 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003103 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3104
3105 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3106 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003107 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003108 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3109 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3110 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3111
3112 lastSelectedLine = curr;
3113 }
3114
3115 if (containsStart && !lastSelectedLine)
3116 // VisibleSelection must start just after our last line.
3117 lastSelectedLine = lastRootBox();
3118
3119 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003120 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003121 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3122 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3123 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3124 }
3125 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003126}
3127
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003128bool RenderBlockFlow::needsLayoutAfterFragmentRangeChange() const
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003129{
3130 // A block without floats or that expands to enclose them won't need a relayout
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003131 // after a fragment range change. There is no overflow content needing relayout
3132 // in the fragment chain because the fragment range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003133 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003134 return false;
3135
3136 return true;
3137}
3138
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003139void RenderBlockFlow::updateLogicalHeight()
3140{
3141 RenderBlock::updateLogicalHeight();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003142}
3143
zalan@apple.com624c2642017-10-05 14:04:27 +00003144void RenderBlockFlow::setMultiColumnFlow(RenderMultiColumnFlow& fragmentedFlow)
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003145{
zalan@apple.com624c2642017-10-05 14:04:27 +00003146 ASSERT(!hasRareBlockFlowData() || !rareBlockFlowData()->m_multiColumnFlow);
3147 ensureRareBlockFlowData().m_multiColumnFlow = makeWeakPtr(fragmentedFlow);
3148}
3149
3150void RenderBlockFlow::clearMultiColumnFlow()
3151{
3152 ASSERT(hasRareBlockFlowData());
3153 ASSERT(rareBlockFlowData()->m_multiColumnFlow);
3154 rareBlockFlowData()->m_multiColumnFlow.clear();
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003155}
3156
akling@apple.com525dae62014-01-03 20:22:09 +00003157static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003158{
akling@apple.com38f0a652014-02-06 21:24:17 +00003159 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003160}
3161
3162RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3163{
3164 ASSERT(i >= 0);
3165
akling@apple.com827be9c2013-10-29 02:58:43 +00003166 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003167 return nullptr;
3168
3169 if (childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003170 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003171 if (!i--)
3172 return box;
3173 }
akling@apple.com525dae62014-01-03 20:22:09 +00003174 return nullptr;
3175 }
3176
3177 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3178 if (!shouldCheckLines(blockFlow))
3179 continue;
3180 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3181 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003182 }
3183
3184 return nullptr;
3185}
3186
3187int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3188{
akling@apple.com827be9c2013-10-29 02:58:43 +00003189 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003190 return 0;
3191
3192 int count = 0;
3193
3194 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003195 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003196 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003197 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003198 }
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003199 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3200 ++count;
weinig@apple.com17140912013-10-19 19:55:40 +00003201 if (box == stopRootInlineBox) {
3202 if (found)
3203 *found = true;
3204 break;
3205 }
3206 }
akling@apple.com525dae62014-01-03 20:22:09 +00003207 return count;
3208 }
3209
3210 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3211 if (!shouldCheckLines(blockFlow))
3212 continue;
3213 bool recursiveFound = false;
3214 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3215 if (recursiveFound) {
3216 if (found)
3217 *found = true;
3218 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003219 }
3220 }
3221
3222 return count;
3223}
3224
3225static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3226{
akling@apple.com827be9c2013-10-29 02:58:43 +00003227 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003228 return -1;
3229
3230 if (block.childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003231 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003232 if (++count == lineCount)
3233 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3234 }
3235 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003236 RenderBox* normalFlowChildWithoutLines = nullptr;
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003237 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003238 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3239 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003240 if (result != -1)
3241 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003242 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003243 normalFlowChildWithoutLines = obj;
3244 }
3245 if (normalFlowChildWithoutLines && !lineCount)
3246 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3247 }
3248
3249 return -1;
3250}
3251
3252int RenderBlockFlow::heightForLineCount(int lineCount)
3253{
3254 int count = 0;
3255 return getHeightForLineCount(*this, lineCount, true, count);
3256}
3257
3258void RenderBlockFlow::clearTruncation()
3259{
akling@apple.com827be9c2013-10-29 02:58:43 +00003260 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003261 return;
3262
3263 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003264 ensureLineBoxes();
3265
weinig@apple.com17140912013-10-19 19:55:40 +00003266 setHasMarkupTruncation(false);
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003267 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
weinig@apple.com17140912013-10-19 19:55:40 +00003268 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003269 return;
3270 }
3271
3272 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3273 if (shouldCheckLines(blockFlow))
3274 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003275 }
3276}
3277
weinig@apple.com3f23b382013-10-19 20:26:58 +00003278bool RenderBlockFlow::containsNonZeroBidiLevel() const
3279{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003280 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3281 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003282 if (box->bidiLevel())
3283 return true;
3284 }
3285 }
3286 return false;
3287}
3288
weinig@apple.com611b9292013-10-20 22:57:54 +00003289Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3290{
3291 if (!box)
3292 return Position();
3293
3294 if (!box->renderer().nonPseudoNode())
3295 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3296
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003297 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003298 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3299
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003300 auto& textBox = downcast<InlineTextBox>(*box);
3301 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003302}
3303
enrica@apple.com0db51a62016-04-27 23:53:08 +00003304RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
3305{
3306 // A light, non-recursive version of RenderBlock::positionForCoordinates that looks at
3307 // whether a point lies within the gaps between its root line boxes, to be called against
3308 // a node returned from elementAtPoint. We make the assumption that either the node or one
3309 // of its immediate children contains the root line boxes in question.
3310 // See <rdar://problem/6824650> for context.
3311
3312 RenderBlock* block = this;
3313
3314 FloatPoint localPoint = block->absoluteToLocal(point);
3315
3316 if (!block->childrenInline()) {
3317 // Look among our immediate children for an alternate box that contains the point.
3318 for (RenderBox* child = block->firstChildBox(); child; child = child->nextSiblingBox()) {
3319 if (!child->height() || child->style().visibility() != WebCore::VISIBLE || child->isFloatingOrOutOfFlowPositioned())
3320 continue;
3321 float top = child->y();
3322
3323 RenderBox* nextChild = child->nextSiblingBox();
3324 while (nextChild && nextChild->isFloatingOrOutOfFlowPositioned())
3325 nextChild = nextChild->nextSiblingBox();
3326 if (!nextChild) {
3327 if (localPoint.y() >= top) {
3328 block = downcast<RenderBlock>(child);
3329 break;
3330 }
3331 continue;
3332 }
3333
3334 float bottom = nextChild->y();
3335
3336 if (localPoint.y() >= top && localPoint.y() < bottom && is<RenderBlock>(*child)) {
3337 block = downcast<RenderBlock>(child);
3338 break;
3339 }
3340 }
3341
3342 if (!block->childrenInline())
3343 return nullptr;
3344
3345 localPoint = block->absoluteToLocal(point);
3346 }
3347
3348 RenderBlockFlow& blockFlow = downcast<RenderBlockFlow>(*block);
3349
3350 // Only check the gaps between the root line boxes. We deliberately ignore overflow because
3351 // experience has shown that hit tests on an exploded text node can fail when within the
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003352 // overflow fragment.
enrica@apple.com0db51a62016-04-27 23:53:08 +00003353 for (RootInlineBox* current = blockFlow.firstRootBox(); current && current != blockFlow.lastRootBox(); current = current->nextRootBox()) {
3354 float currentBottom = current->y() + current->logicalHeight();
3355 if (localPoint.y() < currentBottom)
3356 return nullptr;
3357
3358 RootInlineBox* next = current->nextRootBox();
3359 float nextTop = next->y();
3360 if (localPoint.y() < nextTop) {
3361 InlineBox* inlineBox = current->closestLeafChildForLogicalLeftPosition(localPoint.x());
3362 if (inlineBox && inlineBox->behavesLikeText() && is<RenderText>(inlineBox->renderer()))
3363 return &downcast<RenderText>(inlineBox->renderer());
3364 }
3365 }
3366 return nullptr;
3367}
3368
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003369VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer* fragment)
weinig@apple.com611b9292013-10-20 22:57:54 +00003370{
3371 ASSERT(childrenInline());
3372
antti@apple.com940f5872013-10-24 20:31:11 +00003373 ensureLineBoxes();
3374
weinig@apple.com611b9292013-10-20 22:57:54 +00003375 if (!firstRootBox())
3376 return createVisiblePosition(0, DOWNSTREAM);
3377
akling@apple.com827be9c2013-10-29 02:58:43 +00003378 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3379 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003380
3381 // look for the closest line box in the root box which is at the passed-in y coordinate
3382 InlineBox* closestBox = 0;
3383 RootInlineBox* firstRootBoxWithChildren = 0;
3384 RootInlineBox* lastRootBoxWithChildren = 0;
3385 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003386 if (fragment && root->containingFragment() != fragment)
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003387 continue;
3388
weinig@apple.com611b9292013-10-20 22:57:54 +00003389 if (!root->firstLeafChild())
3390 continue;
3391 if (!firstRootBoxWithChildren)
3392 firstRootBoxWithChildren = root;
3393
3394 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3395 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3396 break;
3397
3398 lastRootBoxWithChildren = root;
3399
3400 // check if this root line box is located at this y coordinate
3401 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3402 if (linesAreFlipped) {
3403 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3404 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3405 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3406
3407 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3408 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3409 continue;
3410 }
3411 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3412 if (closestBox)
3413 break;
3414 }
3415 }
3416
3417 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3418
3419 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3420 // y coordinate is below last root line box, pretend we hit it
3421 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3422 }
3423
3424 if (closestBox) {
3425 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003426 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003427 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3428 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3429 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3430 if (box->isLineBreak()) {
3431 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3432 box = newBox;
3433 }
3434 // y coordinate is above first root line box, so return the start of the first
3435 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3436 }
3437 }
3438
3439 // pass the box a top position that is inside it
3440 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3441 if (!isHorizontalWritingMode())
3442 point = point.transposedPoint();
3443 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003444 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003445 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003446 }
3447
3448 if (lastRootBoxWithChildren) {
3449 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3450 ASSERT(moveCaretToBoundary);
3451 InlineBox* logicallyLastBox;
3452 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3453 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3454 }
3455
3456 // Can't reach this. We have a root line box, but it has no kids.
3457 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3458 // seems to hit this code path.
3459 return createVisiblePosition(0, DOWNSTREAM);
3460}
3461
zalan@apple.com0d5951b2017-02-19 16:24:20 +00003462Position RenderBlockFlow::positionForPoint(const LayoutPoint& point)
3463{
3464 // FIXME: It supports single text child only (which is the majority of simple line layout supported content at this point).
3465 if (!simpleLineLayout() || firstChild() != lastChild() || !is<RenderText>(firstChild()))
3466 return positionForPoint(point, nullptr).deepEquivalent();
3467 return downcast<RenderText>(*firstChild()).positionForPoint(point);
3468}
3469
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003470VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer*)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003471{
antti@apple.come0e8a562017-09-21 18:29:47 +00003472 return RenderBlock::positionForPoint(point, nullptr);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003473}
3474
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003475void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
weinig@apple.com611b9292013-10-20 22:57:54 +00003476{
antti@apple.com940f5872013-10-24 20:31:11 +00003477 ASSERT(childrenInline());
weinig@apple.com611b9292013-10-20 22:57:54 +00003478 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003479 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3480 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003481 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3482 if (!rect.isEmpty())
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003483 rects.append(rect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003484 }
3485}
3486
3487void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3488{
3489 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003490
darin@apple.come1be6ca2014-04-28 04:19:10 +00003491 if (auto simpleLineLayout = this->simpleLineLayout()) {
3492 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003493 return;
3494 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003495 m_lineBoxes.paint(this, paintInfo, paintOffset);
3496}
3497
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003498bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003499{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003500 if (!multiColumnFlow() || !multiColumnFlow()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003501 return false;
3502
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003503 multiColumnFlow()->setNeedsHeightsRecalculation(false);
3504 multiColumnFlow()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003505
3506 bool needsRelayout;
3507 bool neededRelayout = false;
3508 bool firstPass = true;
3509 do {
3510 // Column heights may change here because of balancing. We may have to do multiple layout
3511 // passes, depending on how the contents is fitted to the changed column heights. In most
3512 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3513 // passes than that, though, but the number of retries should not exceed the number of
3514 // columns, unless we have a bug.
3515 needsRelayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003516 for (RenderMultiColumnSet* multicolSet = multiColumnFlow()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003517 if (multicolSet->recalculateColumnHeight(firstPass))
3518 needsRelayout = true;
3519 if (needsRelayout) {
3520 // Once a column set gets a new column height, that column set and all successive column
3521 // sets need to be laid out over again, since their logical top will be affected by
3522 // this, and therefore their column heights may change as well, at least if the multicol
3523 // height is constrained.
3524 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003525 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003526 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003527 if (needsRelayout) {
3528 // Layout again. Column balancing resulted in a new height.
3529 neededRelayout = true;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003530 multiColumnFlow()->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003531 setChildNeedsLayout(MarkOnlyThis);
3532 if (firstPass)
3533 statePusher.pop();
3534 layoutBlock(false);
3535 }
3536 firstPass = false;
3537 } while (needsRelayout);
3538
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003539 multiColumnFlow()->setInBalancingPass(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003540
3541 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003542}
3543
antti@apple.com940f5872013-10-24 20:31:11 +00003544bool RenderBlockFlow::hasLines() const
3545{
zalan@apple.coma2fe1762016-08-24 18:33:43 +00003546 if (!childrenInline())
3547 return false;
antti@apple.com940f5872013-10-24 20:31:11 +00003548
darin@apple.come1be6ca2014-04-28 04:19:10 +00003549 if (auto simpleLineLayout = this->simpleLineLayout())
3550 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003551
3552 return lineBoxes().firstLineBox();
3553}
3554
antti@apple.com9e891c82014-05-22 06:12:34 +00003555void RenderBlockFlow::invalidateLineLayoutPath()
3556{
akling@apple.coma12fee22015-02-01 02:58:13 +00003557 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003558 case UndeterminedPath:
3559 case ForceLineBoxesPath:
3560 ASSERT(!m_simpleLineLayout);
3561 return;
3562 case LineBoxesPath:
3563 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003564 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003565 return;
3566 case SimpleLinesPath:
3567 // The simple line layout may have become invalid.
3568 m_simpleLineLayout = nullptr;
akling@apple.coma12fee22015-02-01 02:58:13 +00003569 setLineLayoutPath(UndeterminedPath);
zalan@apple.comde191042017-06-06 19:35:56 +00003570 if (needsLayout())
3571 return;
3572 // FIXME: We should just kick off a subtree layout here (if needed at all) see webkit.org/b/172947.
3573 setNeedsLayout();
antti@apple.com9e891c82014-05-22 06:12:34 +00003574 return;
3575 }
3576 ASSERT_NOT_REACHED();
3577}
3578
zalan@apple.come37da962014-12-11 03:29:29 +00003579void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003580{
zalan@apple.come37da962014-12-11 03:29:29 +00003581 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3582 if (needsLayout) {
3583 deleteLineBoxesBeforeSimpleLineLayout();
3584 m_simpleLineLayout = SimpleLineLayout::create(*this);
3585 }
ryanhaddad@apple.com224f2ea2017-11-06 21:44:34 +00003586 if (view().layoutState() && view().layoutState()->isPaginated()) {
zalan@apple.com5cd09e52017-02-25 02:14:40 +00003587 m_simpleLineLayout->setIsPaginated();
3588 SimpleLineLayout::adjustLinePositionsForPagination(*m_simpleLineLayout, *this);
3589 }
zalan@apple.comd6ab7b52016-11-01 05:35:48 +00003590 for (auto& renderer : childrenOfType<RenderObject>(*this))
3591 renderer.clearNeedsLayout();
antti@apple.com940f5872013-10-24 20:31:11 +00003592 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00003593 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003594 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003595 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003596 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003597 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3598}
3599
3600void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3601{
akling@apple.coma12fee22015-02-01 02:58:13 +00003602 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003603 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003604 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3605 if (is<RenderText>(renderer))
3606 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3607 else if (is<RenderLineBreak>(renderer))
3608 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3609 else
3610 ASSERT_NOT_REACHED();
3611 }
antti@apple.com940f5872013-10-24 20:31:11 +00003612}
3613
3614void RenderBlockFlow::ensureLineBoxes()
3615{
akling@apple.coma12fee22015-02-01 02:58:13 +00003616 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003617 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003618 return;
zalan@apple.comfa5add62017-02-22 19:33:02 +00003619 bool isPaginated = m_simpleLineLayout->isPaginated();
antti@apple.comfea51992013-10-28 13:39:23 +00003620 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003621
3622#if !ASSERT_DISABLED
3623 LayoutUnit oldHeight = logicalHeight();
3624#endif
3625 bool didNeedLayout = needsLayout();
3626
3627 bool relayoutChildren = false;
3628 LayoutUnit repaintLogicalTop;
3629 LayoutUnit repaintLogicalBottom;
zalan@apple.comfa5add62017-02-22 19:33:02 +00003630 if (isPaginated) {
zalan@apple.com6c04c202017-05-01 00:15:38 +00003631 PaginatedLayoutStateMaintainer state(*this);
zalan@apple.comfa5add62017-02-22 19:33:02 +00003632 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
zalan@apple.come9f08212017-04-27 11:02:09 +00003633 // This matches relayoutToAvoidWidows.
3634 if (shouldBreakAtLineToAvoidWidow())
3635 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
zalan@apple.comb16bcdc2017-07-21 21:04:43 +00003636 // FIXME: This is needed as long as simple and normal line layout produce different line breakings.
3637 repaint();
zalan@apple.comfa5add62017-02-22 19:33:02 +00003638 } else
3639 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +00003640
3641 updateLogicalHeight();
3642 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3643
3644 if (!didNeedLayout)
3645 clearNeedsLayout();
3646}
3647
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003648#if ENABLE(TREE_DEBUGGING)
don.olmstead@sony.comd57eb472017-08-10 01:15:14 +00003649void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003650{
weinig@apple.com611b9292013-10-20 22:57:54 +00003651 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.com360de752017-07-06 21:13:24 +00003652 root->outputLineTreeAndMark(stream, markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003653
3654 if (auto simpleLineLayout = this->simpleLineLayout())
zalan@apple.com360de752017-07-06 21:13:24 +00003655 SimpleLineLayout::outputLineLayoutForFlow(stream, *this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003656}
3657#endif
3658
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003659RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3660{
3661 if (hasRareBlockFlowData())
3662 return *m_rareBlockFlowData;
3663 materializeRareBlockFlowData();
3664 return *m_rareBlockFlowData;
3665}
3666
3667void RenderBlockFlow::materializeRareBlockFlowData()
3668{
3669 ASSERT(!hasRareBlockFlowData());
3670 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3671}
3672
dbates@webkit.org102013c2016-09-26 21:51:25 +00003673#if ENABLE(TEXT_AUTOSIZING)
cdumez@apple.com83102df2016-05-19 19:09:41 +00003674static inline bool isVisibleRenderText(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003675{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003676 if (!is<RenderText>(renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003677 return false;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003678
3679 auto& renderText = downcast<RenderText>(renderer);
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003680 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003681}
3682
cdumez@apple.com83102df2016-05-19 19:09:41 +00003683static inline bool resizeTextPermitted(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003684{
3685 // 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 +00003686 for (auto* ancestor = renderer.parent(); ancestor; ancestor = ancestor->parent()) {
aestes@apple.com6751d842014-01-12 02:51:25 +00003687 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.com83102df2016-05-19 19:09:41 +00003688 if (is<HTMLElement>(ancestor->element()) && !ancestor->element()->isInShadowTree()) {
3689 auto& element = downcast<HTMLElement>(*ancestor->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003690 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003691 }
aestes@apple.com6751d842014-01-12 02:51:25 +00003692 }
3693 return true;
3694}
3695
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003696int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003697{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003698 if (style().visibility() != VISIBLE)
3699 return 0;
3700 if (childrenInline())
3701 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003702 // Only descend into list items.
3703 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003704 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3705 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003706 return count;
3707}
3708
cdumez@apple.com83102df2016-05-19 19:09:41 +00003709static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003710{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003711 if (!renderer.isRenderBlock())
aestes@apple.com6751d842014-01-12 02:51:25 +00003712 return true;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003713 if (renderer.isListItem())
3714 return renderer.style().height().type() != Fixed;
aestes@apple.com6751d842014-01-12 02:51:25 +00003715 return false;
3716}
3717
3718// For now, we auto size single lines of text the same as multiple lines.
3719// We've been experimenting with low values for single lines of text.
3720static inline float oneLineTextMultiplier(float specifiedSize)
3721{
3722 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3723}
3724
3725static inline float textMultiplier(float specifiedSize)
3726{
3727 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3728}
3729
3730void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3731{
simon.fraser@apple.com36676e52016-05-07 00:05:58 +00003732 LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
3733
aestes@apple.com6751d842014-01-12 02:51:25 +00003734 // Don't do any work if the block is smaller than the visible area.
3735 if (visibleWidth >= width())
3736 return;
3737
3738 unsigned lineCount;
3739 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003740 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003741 if (!count)
3742 lineCount = NO_LINE;
3743 else if (count == 1)
3744 lineCount = ONE_LINE;
3745 else
3746 lineCount = MULTI_LINE;
3747 } else
3748 lineCount = m_lineCountForTextAutosizing;
3749
3750 ASSERT(lineCount != NOT_SET);
3751 if (lineCount == NO_LINE)
3752 return;
3753
3754 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3755 float scale = visibleWidth / actualWidth;
3756 float minFontSize = roundf(size / scale);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003757
3758 for (auto* descendant = RenderObjectTraversal::firstChild(*this); descendant; ) {
3759 if (!isNonBlocksOrNonFixedHeightListItems(*descendant)) {
3760 descendant = RenderObjectTraversal::nextSkippingChildren(*descendant, this);
3761 continue;
aestes@apple.com6751d842014-01-12 02:51:25 +00003762 }
cdumez@apple.com83102df2016-05-19 19:09:41 +00003763 if (!isVisibleRenderText(*descendant) || !resizeTextPermitted(*descendant)) {
3764 descendant = RenderObjectTraversal::next(*descendant, this);
3765 continue;
3766 }
3767
3768 auto& text = downcast<RenderText>(*descendant);
3769 auto& oldStyle = text.style();
3770 auto& fontDescription = oldStyle.fontDescription();
3771 float specifiedSize = fontDescription.specifiedSize();
3772 float scaledSize = roundf(specifiedSize * scale);
3773 if (scaledSize > 0 && scaledSize < minFontSize) {
3774 // 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.
3775 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3776 if (m_lineCountForTextAutosizing == NOT_SET)
3777 m_lineCountForTextAutosizing = lineCount;
3778 if (m_widthForTextAutosizing == -1)
3779 m_widthForTextAutosizing = actualWidth;
3780
3781 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3782 float candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
3783 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
antti@apple.com4918b4d2017-08-14 13:20:47 +00003784 document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003785 }
3786
3787 descendant = RenderObjectTraversal::nextSkippingChildren(text, this);
aestes@apple.com6751d842014-01-12 02:51:25 +00003788 }
3789}
dbates@webkit.org102013c2016-09-26 21:51:25 +00003790#endif // ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +00003791
hyatt@apple.com80914862017-03-06 18:00:35 +00003792void RenderBlockFlow::layoutExcludedChildren(bool relayoutChildren)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003793{
hyatt@apple.com80914862017-03-06 18:00:35 +00003794 RenderBlock::layoutExcludedChildren(relayoutChildren);
3795
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003796 auto* fragmentedFlow = multiColumnFlow();
3797 if (!fragmentedFlow)
hyatt@apple.com80914862017-03-06 18:00:35 +00003798 return;
3799
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003800 fragmentedFlow->setIsExcludedFromNormalLayout(true);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003801
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003802 setLogicalTopForChild(*fragmentedFlow, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003803
3804 if (relayoutChildren)
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003805 fragmentedFlow->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003806
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003807 if (fragmentedFlow->needsLayout()) {
3808 for (RenderMultiColumnSet* columnSet = fragmentedFlow->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3809 columnSet->prepareForLayout(!fragmentedFlow->inBalancingPass());
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003810
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003811 fragmentedFlow->invalidateFragments(MarkOnlyThis);
3812 fragmentedFlow->setNeedsHeightsRecalculation(true);
3813 fragmentedFlow->layout();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003814 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003815 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3816 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3817 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3818 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3819 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3820 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3821 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3822 // runs get deleted right after every pass.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003823 fragmentedFlow->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003824 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003825 determineLogicalLeftPositionForChild(*fragmentedFlow);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003826}
3827
antti@apple.com6a146b62017-09-30 06:45:59 +00003828void RenderBlockFlow::addChild(RenderPtr<RenderObject> newChild, RenderObject* beforeChild)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003829{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003830 if (multiColumnFlow() && (!isFieldset() || !newChild->isLegend()))
antti@apple.com6a146b62017-09-30 06:45:59 +00003831 return multiColumnFlow()->addChild(WTFMove(newChild), beforeChild);
zalan@apple.comba6049c2017-01-28 16:26:48 +00003832 auto* beforeChildOrPlaceholder = beforeChild;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003833 if (auto* containingFragmentedFlow = enclosingFragmentedFlow())
3834 beforeChildOrPlaceholder = containingFragmentedFlow->resolveMovedChild(beforeChild);
antti@apple.com6a146b62017-09-30 06:45:59 +00003835 RenderBlock::addChild(WTFMove(newChild), beforeChildOrPlaceholder);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003836}
3837
antti@apple.com6a146b62017-09-30 06:45:59 +00003838RenderPtr<RenderObject> RenderBlockFlow::takeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003839{
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +00003840 if (!renderTreeBeingDestroyed()) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003841 RenderFragmentedFlow* fragmentedFlow = multiColumnFlow();
3842 if (fragmentedFlow && fragmentedFlow != &oldChild)
3843 fragmentedFlow->fragmentedFlowRelativeWillBeRemoved(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003844 }
antti@apple.com6a146b62017-09-30 06:45:59 +00003845 return RenderBlock::takeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003846}
3847
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003848void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003849{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003850 // If we don't use columns or flow threads, then bail.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003851 if (!isRenderFragmentedFlow() && !multiColumnFlow())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003852 return;
3853
3854 // 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 +00003855 if (RenderMultiColumnFlow* fragmentedFlow = multiColumnFlow()) {
zalan@apple.com53e79072016-12-12 20:17:50 +00003856 LayoutUnit newColumnHeight;
3857 if (hasDefiniteLogicalHeight() || view().frameView().pagination().mode != Pagination::Unpaginated) {
zalan@apple.comcca4b692016-12-16 04:37:28 +00003858 auto computedValues = computeLogicalHeight(LayoutUnit(), logicalTop());
zalan@apple.com53e79072016-12-12 20:17:50 +00003859 newColumnHeight = std::max<LayoutUnit>(computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(), 0);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003860 if (fragmentedFlow->columnHeightAvailable() != newColumnHeight)
zalan@apple.com53e79072016-12-12 20:17:50 +00003861 relayoutChildren = true;
3862 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003863 fragmentedFlow->setColumnHeightAvailable(newColumnHeight);
3864 } else if (is<RenderFragmentedFlow>(*this)) {
3865 RenderFragmentedFlow& fragmentedFlow = downcast<RenderFragmentedFlow>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003866
3867 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3868 // is known. The page logical height thing in LayoutState is meaningless for flow
3869 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3870 // thread), but as long as it is used universally as a means to determine whether page
3871 // height is known or not, we need this. Page height is unknown when column balancing is
3872 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3873 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3874 // 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 +00003875 // hack once the old multicol implementation is gone (see also RenderView::pushLayoutStateForPagination).
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003876 pageLogicalHeight = fragmentedFlow.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003877
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003878 pageLogicalHeightChanged = fragmentedFlow.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003879 }
3880}
3881
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003882bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
zalan@apple.com809f4872016-12-08 18:20:01 +00003883{
3884 return willCreateColumns(desiredColumnCount);
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003885}
3886
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003887void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3888{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003889 ASSERT(!!multiColumnFlow() == requiresColumns(count));
3890 if (!multiColumnFlow())
antti@apple.com411949d2017-08-30 17:28:10 +00003891 return;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003892 multiColumnFlow()->setColumnCountAndWidth(count, width);
3893 multiColumnFlow()->setProgressionIsInline(style().hasInlineColumnAxis());
3894 multiColumnFlow()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003895}
3896
cdumez@apple.com78141732014-11-04 23:00:48 +00003897void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003898{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003899 if (!multiColumnFlow())
hyatt@apple.com86919862014-01-27 16:27:45 +00003900 return;
3901
3902 bool needsLayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003903 bool oldProgressionIsInline = multiColumnFlow()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003904 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003905 if (oldProgressionIsInline != newProgressionIsInline) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003906 multiColumnFlow()->setProgressionIsInline(newProgressionIsInline);
hyatt@apple.com86919862014-01-27 16:27:45 +00003907 needsLayout = true;
3908 }
3909
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003910 bool oldProgressionIsReversed = multiColumnFlow()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003911 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003912 if (oldProgressionIsReversed != newProgressionIsReversed) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003913 multiColumnFlow()->setProgressionIsReversed(newProgressionIsReversed);
hyatt@apple.com86919862014-01-27 16:27:45 +00003914 needsLayout = true;
3915 }
3916
3917 if (needsLayout)
3918 setNeedsLayoutAndPrefWidthsRecalc();
3919}
3920
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003921LayoutUnit RenderBlockFlow::computedColumnWidth() const
3922{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003923 if (multiColumnFlow())
3924 return multiColumnFlow()->computedColumnWidth();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003925 return contentLogicalWidth();
3926}
3927
3928unsigned RenderBlockFlow::computedColumnCount() const
3929{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003930 if (multiColumnFlow())
3931 return multiColumnFlow()->computedColumnCount();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003932
3933 return 1;
3934}
3935
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003936bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3937{
3938 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003939 if (!multiColumnFlow() || style().columnProgression() == NormalColumnProgression)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003940 return hasTopOverflow;
3941
3942 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3943 hasTopOverflow = !hasTopOverflow;
3944
3945 return hasTopOverflow;
3946}
3947
3948bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3949{
3950 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003951 if (!multiColumnFlow() || style().columnProgression() == NormalColumnProgression)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003952 return hasLeftOverflow;
3953
3954 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3955 hasLeftOverflow = !hasLeftOverflow;
3956
3957 return hasLeftOverflow;
3958}
3959
zalan@apple.comac6956c2014-09-05 14:18:06 +00003960struct InlineMinMaxIterator {
3961/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3962 inline min/max width calculations. Note the following about the way it walks:
3963 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3964 (2) We do not drill into the children of floats or replaced elements, since you can't break
3965 in the middle of such an element.
3966 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3967 distinct borders/margin/padding that contribute to the min/max width.
3968*/
3969 const RenderBlockFlow& parent;
3970 RenderObject* current;
3971 bool endOfInline;
3972 bool initial;
3973
3974 InlineMinMaxIterator(const RenderBlockFlow& p)
3975 : parent(p)
3976 , current(nullptr)
3977 , endOfInline(false)
3978 , initial(true)
3979 { }
3980
3981 RenderObject* next();
3982};
3983
3984RenderObject* InlineMinMaxIterator::next()
3985{
3986 RenderObject* result = nullptr;
3987 bool oldEndOfInline = endOfInline;
3988 endOfInline = false;
3989 do {
3990 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3991 result = current->firstChildSlow();
3992 else if (initial) {
3993 result = parent.firstChild();
3994 initial = false;
3995 }
3996
3997 if (!result) {
3998 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3999 if (!oldEndOfInline && current && current->isRenderInline()) {
4000 result = current;
4001 endOfInline = true;
4002 break;
4003 }
4004
4005 while (current && current != &parent) {
4006 result = current->nextSibling();
4007 if (result)
4008 break;
4009 current = current->parent();
4010 if (current && current != &parent && current->isRenderInline()) {
4011 result = current;
4012 endOfInline = true;
4013 break;
4014 }
4015 }
4016 }
4017
4018 if (!result)
4019 break;
4020
4021 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4022 break;
4023
4024 current = result;
4025 result = nullptr;
4026 } while (current || current == &parent);
4027 // Update our position.
4028 current = result;
4029 return result;
4030}
4031
4032static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4033{
4034 if (cssUnit.type() != Auto)
4035 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4036 return 0;
4037}
4038
4039static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4040{
4041 const RenderStyle& childStyle = child.style();
4042 if (endOfInline) {
4043 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4044 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4045 child.borderEnd();
4046 }
4047 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4048 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4049 child.borderStart();
4050}
4051
4052static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4053{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004054 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004055 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004056 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004057 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004058 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
mmaxfield@apple.com21a4dcb2016-03-13 00:36:59 +00004059 float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004060 inlineMax -= spaceWidth + font.wordSpacing();
4061 if (inlineMin > inlineMax)
4062 inlineMin = inlineMax;
4063 }
4064}
4065
4066static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4067{
4068 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4069}
4070
4071void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4072{
4073 float inlineMax = 0;
4074 float inlineMin = 0;
4075
4076 const RenderStyle& styleToUse = style();
4077 RenderBlock* containingBlock = this->containingBlock();
4078 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4079
4080 // If we are at the start of a line, we want to ignore all white-space.
4081 // Also strip spaces if we previously had text that ended in a trailing space.
4082 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004083 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004084
4085 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4086 // very specific cirucumstances (in order to match common WinIE renderings).
4087 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4088 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4089
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004090 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004091
4092 InlineMinMaxIterator childIterator(*this);
4093
4094 // Only gets added to the max preffered width once.
4095 bool addedTextIndent = false;
4096 // Signals the text indent was more negative than the min preferred width
4097 bool hasRemainingNegativeTextIndent = false;
4098
4099 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4100 RenderObject* prevFloat = 0;
4101 bool isPrevChildInlineFlow = false;
4102 bool shouldBreakLineAfterText = false;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004103 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation() & FirstHangingPunctuation;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004104 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation() & LastHangingPunctuation;
4105 RenderText* lastText = nullptr;
4106
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004107 bool addedStartPunctuationHang = false;
4108
zalan@apple.comac6956c2014-09-05 14:18:06 +00004109 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004110 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004111 child->style().autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004112 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004113 // Step One: determine whether or not we need to terminate our current line.
4114 // Each discrete chunk can become the new min-width, if it is the widest chunk
4115 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004116
4117 // Children fall into three categories:
4118 // (1) An inline flow object. These objects always have a min/max of 0,
4119 // and are included in the iteration solely so that their margins can
4120 // be added in.
4121 //
4122 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4123 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004124 // we need to break the current line, and then add in our own margins and min/max
4125 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004126 //
4127 // (3) A text object. Text runs can have breakable characters at the start,
4128 // the middle or the end. They may also lose whitespace off the front if
4129 // we're already ignoring whitespace. In order to compute accurate min-width
4130 // information, we need three pieces of information.
4131 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4132 // starts with whitespace.
4133 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4134 // ends with whitespace.
4135 // (c) the min/max width of the string (trimmed for whitespace).
4136 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004137 // If the text string starts with whitespace, then we need to terminate our current line
4138 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004139 //
4140 // If the text string has a breakable character in the middle, but didn't start
4141 // with whitespace, then we add the width of the first non-breakable run and
4142 // then end the current line. We then need to use the intermediate min/max width
4143 // values (if any of them are larger than our current min/max). We then look at
4144 // the width of the last non-breakable run and use that to start a new line
4145 // (unless we end in whitespace).
4146 const RenderStyle& childStyle = child->style();
4147 float childMin = 0;
4148 float childMax = 0;
4149
4150 if (!child->isText()) {
4151 if (child->isLineBreakOpportunity()) {
4152 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4153 inlineMin = 0;
4154 continue;
4155 }
4156 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004157 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004158 // Add in padding/border/margin from the appropriate side of
4159 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004160 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004161 childMin += bpm;
4162 childMax += bpm;
4163
4164 inlineMin += childMin;
4165 inlineMax += childMax;
4166
4167 child->setPreferredLogicalWidthsDirty(false);
4168 } else {
4169 // Inline replaced elts add in their margins to their min/max values.
hyatt@apple.com14520e42016-04-20 18:01:40 +00004170 if (!child->isFloating())
4171 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004172 LayoutUnit margins = 0;
4173 Length startMargin = childStyle.marginStart();
4174 Length endMargin = childStyle.marginEnd();
4175 if (startMargin.isFixed())
4176 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4177 if (endMargin.isFixed())
4178 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4179 childMin += margins.ceilToFloat();
4180 childMax += margins.ceilToFloat();
4181 }
4182 }
4183
cdumez@apple.comf8022152014-10-15 00:29:51 +00004184 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004185 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004186 // Terminate the current line as far as minwidth is concerned.
hyatt@apple.com247170f2017-02-28 16:23:15 +00004187 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4188 computeChildPreferredLogicalWidths(*child, childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth);
4189 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4190 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004191
4192 bool clearPreviousFloat;
4193 if (child->isFloating()) {
4194 clearPreviousFloat = (prevFloat
4195 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4196 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4197 prevFloat = child;
4198 } else
4199 clearPreviousFloat = false;
4200
4201 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
antti@apple.comae85e112017-08-31 23:27:02 +00004202 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004203 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4204 inlineMin = 0;
4205 }
4206
4207 // If we're supposed to clear the previous float, then terminate maxwidth as well.
antti@apple.comae85e112017-08-31 23:27:02 +00004208 if (clearPreviousFloat) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004209 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4210 inlineMax = 0;
4211 }
4212
4213 // Add in text-indent. This is added in only once.
antti@apple.comae85e112017-08-31 23:27:02 +00004214 if (!addedTextIndent && !child->isFloating()) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004215 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4216 childMin += ceiledIndent;
4217 childMax += ceiledIndent;
4218
4219 if (childMin < 0)
4220 textIndent = LayoutUnit::fromFloatCeil(childMin);
4221 else
4222 addedTextIndent = true;
4223 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004224
antti@apple.comae85e112017-08-31 23:27:02 +00004225 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating())
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004226 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004227
4228 // Add our width to the max.
4229 inlineMax += std::max<float>(0, childMax);
4230
antti@apple.comae85e112017-08-31 23:27:02 +00004231 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText))) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004232 if (child->isFloating())
4233 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4234 else
4235 inlineMin += childMin;
4236 } else {
4237 // Now check our line.
4238 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4239
4240 // Now start a new line.
antti@apple.comae85e112017-08-31 23:27:02 +00004241 inlineMin = 0;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004242 }
4243
4244 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4245 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4246 inlineMin = 0;
4247 }
4248
4249 // We are no longer stripping whitespace at the start of a line.
4250 if (!child->isFloating()) {
4251 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004252 trailingSpaceChild = nullptr;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004253 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004254 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004255 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004256 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004257 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004258
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004259 if (renderText.style().hasTextCombine() && renderText.isCombineText())
zalan@apple.com6cad78f2017-09-19 20:28:29 +00004260 downcast<RenderCombineText>(renderText).combineTextIfNeeded();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004261
4262 // Determine if we have a breakable character. Pass in
4263 // whether or not we should ignore any spaces at the front
4264 // of the string. If those are going to be stripped out,
4265 // then they shouldn't be considered in the breakable char
4266 // check.
4267 bool hasBreakableChar, hasBreak;
4268 float beginMin, endMin;
4269 bool beginWS, endWS;
4270 float beginMax, endMax;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004271 bool strippingBeginWS = stripFrontSpaces;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004272 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004273 hasBreakableChar, hasBreak, beginMax, endMax,
4274 childMin, childMax, stripFrontSpaces);
4275
4276 // This text object will not be rendered, but it may still provide a breaking opportunity.
4277 if (!hasBreak && !childMax) {
4278 if (autoWrap && (beginWS || endWS)) {
4279 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4280 inlineMin = 0;
4281 }
4282 continue;
4283 }
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004284
4285 lastText = &renderText;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004286
4287 if (stripFrontSpaces)
4288 trailingSpaceChild = child;
4289 else
4290 trailingSpaceChild = 0;
4291
4292 // Add in text-indent. This is added in only once.
4293 float ti = 0;
4294 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4295 ti = textIndent.ceilToFloat();
4296 childMin += ti;
4297 beginMin += ti;
4298
4299 // It the text indent negative and larger than the child minimum, we re-use the remainder
4300 // in future minimum calculations, but using the negative value again on the maximum
4301 // will lead to under-counting the max pref width.
4302 if (!addedTextIndent) {
4303 childMax += ti;
4304 beginMax += ti;
4305 addedTextIndent = true;
4306 }
4307
4308 if (childMin < 0) {
4309 textIndent = childMin;
4310 hasRemainingNegativeTextIndent = true;
4311 }
4312 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004313
4314 // See if we have a hanging punctuation situation at the start.
4315 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004316 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4317 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004318 childMin -= hangStartWidth;
4319 beginMin -= hangStartWidth;
4320 childMax -= hangStartWidth;
4321 beginMax -= hangStartWidth;
4322 addedStartPunctuationHang = true;
4323 }
4324
zalan@apple.comac6956c2014-09-05 14:18:06 +00004325 // If we have no breakable characters at all,
4326 // then this is the easy case. We add ourselves to the current
4327 // min and max and continue.
4328 if (!hasBreakableChar)
4329 inlineMin += childMin;
4330 else {
4331 // We have a breakable character. Now we need to know if
4332 // we start and end with whitespace.
4333 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004334 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004335 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4336 } else {
4337 inlineMin += beginMin;
4338 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4339 childMin -= ti;
4340 }
4341
4342 inlineMin = childMin;
4343
4344 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004345 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004346 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4347 inlineMin = 0;
4348 shouldBreakLineAfterText = false;
4349 } else {
4350 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4351 inlineMin = endMin;
4352 shouldBreakLineAfterText = true;
4353 }
4354 }
4355
4356 if (hasBreak) {
4357 inlineMax += beginMax;
4358 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4359 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4360 inlineMax = endMax;
4361 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004362 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004363 } else
4364 inlineMax += std::max<float>(0, childMax);
4365 }
4366
antti@apple.comae85e112017-08-31 23:27:02 +00004367 // Ignore spaces after a list marker.
4368 if (child->isListMarker())
zalan@apple.comac6956c2014-09-05 14:18:06 +00004369 stripFrontSpaces = true;
4370 } else {
4371 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4372 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4373 inlineMin = inlineMax = 0;
4374 stripFrontSpaces = true;
4375 trailingSpaceChild = 0;
4376 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004377 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004378 }
4379
4380 if (!child->isText() && child->isRenderInline())
4381 isPrevChildInlineFlow = true;
4382 else
4383 isPrevChildInlineFlow = false;
4384
4385 oldAutoWrap = autoWrap;
4386 }
4387
4388 if (styleToUse.collapseWhiteSpace())
4389 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004390
4391 if (canHangPunctuationAtEnd && lastText && lastText->textLength() > 0) {
4392 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->textLength() - 1;
4393 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4394 inlineMin -= endHangWidth;
4395 inlineMax -= endHangWidth;
4396 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004397
4398 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4399 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4400}
4401
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004402}
4403// namespace WebCore