blob: 62c3856a08050740b969ab37a6786e006dbf6326 [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
zalan@apple.com6c04c202017-05-01 00:15:38 +000070class PaginatedLayoutStateMaintainer {
71public:
72 PaginatedLayoutStateMaintainer(RenderBlockFlow& flow)
73 : m_flow(flow)
74 , m_pushed(flow.view().pushLayoutStateForPaginationIfNeeded(flow))
75 {
76 }
77
78 ~PaginatedLayoutStateMaintainer()
79 {
80 if (m_pushed)
81 m_flow.view().popLayoutState(m_flow);
82 }
83
84private:
85 RenderBlockFlow& m_flow;
86 bool m_pushed { false };
87};
88
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000089// Our MarginInfo state used when laying out block children.
hyatt@apple.com9a79c622015-09-15 18:38:18 +000090RenderBlockFlow::MarginInfo::MarginInfo(const RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000091 : m_atBeforeSideOfBlock(true)
92 , m_atAfterSideOfBlock(false)
93 , m_hasMarginBeforeQuirk(false)
94 , m_hasMarginAfterQuirk(false)
95 , m_determinedMarginBeforeQuirk(false)
96 , m_discardMargin(false)
97{
akling@apple.com827be9c2013-10-29 02:58:43 +000098 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000099 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000100 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000101
akling@apple.com827be9c2013-10-29 02:58:43 +0000102 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000103
104 // If any height other than auto is specified in CSS, then we don't collapse our bottom
105 // margins with our children's margins. To do otherwise would be to risk odd visual
106 // effects when the children overflow out of the parent block and yet still collapse
107 // with it. We also don't collapse if we have any bottom border/padding.
108 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +0000109 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000110
weinig@apple.com12840dc2013-10-22 23:59:08 +0000111 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000112
weinig@apple.com12840dc2013-10-22 23:59:08 +0000113 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000114
weinig@apple.com12840dc2013-10-22 23:59:08 +0000115 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
116 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000117}
118
antti@apple.com454418f2016-04-25 19:49:23 +0000119RenderBlockFlow::RenderBlockFlow(Element& element, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000120 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
dbates@webkit.org102013c2016-09-26 21:51:25 +0000121#if ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +0000122 , m_widthForTextAutosizing(-1)
123 , m_lineCountForTextAutosizing(NOT_SET)
124#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000125{
weinig@apple.com611b9292013-10-20 22:57:54 +0000126 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000127}
128
antti@apple.com454418f2016-04-25 19:49:23 +0000129RenderBlockFlow::RenderBlockFlow(Document& document, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000130 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
dbates@webkit.org102013c2016-09-26 21:51:25 +0000131#if ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +0000132 , m_widthForTextAutosizing(-1)
133 , m_lineCountForTextAutosizing(NOT_SET)
134#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000135{
weinig@apple.com611b9292013-10-20 22:57:54 +0000136 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000137}
138
139RenderBlockFlow::~RenderBlockFlow()
140{
simon.fraser@apple.com9812a452017-03-20 17:28:55 +0000141 // Do not add any code here. Add it to willBeDestroyed() instead.
hyatt@apple.com5388e672013-09-06 20:54:47 +0000142}
143
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000144void RenderBlockFlow::insertedIntoTree()
145{
146 RenderBlock::insertedIntoTree();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000147}
148
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000149void RenderBlockFlow::willBeDestroyed()
150{
weinig@apple.com611b9292013-10-20 22:57:54 +0000151 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
152 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
153 destroyLeftoverChildren();
154
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +0000155 if (!renderTreeBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000156 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000157 // We can't wait for RenderBox::destroy to clear the selection,
158 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000159 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000160 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000161
162 // If we are an anonymous block, then our line boxes might have children
163 // that will outlast this block. In the non-anonymous block case those
164 // children will be destroyed by the time we return from this function.
165 if (isAnonymousBlock()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +0000166 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000167 while (auto childBox = box->firstChild())
168 childBox->removeFromParent();
169 }
170 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000171 } else if (parent())
172 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000173 }
174
akling@apple.com31dd4f42013-10-30 22:27:59 +0000175 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000176
simon.fraser@apple.com9812a452017-03-20 17:28:55 +0000177 blockWillBeDestroyed();
weinig@apple.com611b9292013-10-20 22:57:54 +0000178
179 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
180 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000181}
182
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000183RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
184{
185 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
186 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
187 // to avoid floats.
188 parentHasFloats = false;
189 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
190 if (is<RenderBlockFlow>(*sibling)) {
191 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
192 if (!siblingBlock.avoidsFloats())
193 return &siblingBlock;
194 }
195 if (sibling->isFloating())
196 parentHasFloats = true;
197 }
198 return nullptr;
199}
200
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000201void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000202{
203 if (m_floatingObjects)
204 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
205
206 HashSet<RenderBox*> oldIntrudingFloatSet;
207 if (!childrenInline() && m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000208 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
209 auto end = floatingObjectSet.end();
210 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
211 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000212 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000213 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000214 }
215 }
216
217 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000218 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000219 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000220 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000221 if (!oldIntrudingFloatSet.isEmpty())
222 markAllDescendantsWithFloatsForLayout();
223 return;
224 }
225
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000226 RendererToFloatInfoMap floatMap;
227
228 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000229 if (childrenInline())
230 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
231 else
232 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000233 }
234
235 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
236 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
237 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
antti@apple.comae85e112017-08-31 23:27:02 +0000238 if (!is<RenderBlockFlow>(parent()))
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000239 return;
240
robert@webkit.org97037ef2013-11-20 19:26:10 +0000241 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
242 // them (as opposed to floats they contain themselves) so check for those here too.
antti@apple.comae85e112017-08-31 23:27:02 +0000243 auto& parentBlock = downcast<RenderBlockFlow>(*parent());
244 bool parentHasFloats = false;
245 RenderBlockFlow* previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000246 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000247 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000248 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000249
250 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000251 if (previousBlock)
252 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000253 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000254 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000255 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000256 }
257
258 // 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 +0000259 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000260 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000261
262 if (childrenInline()) {
263 LayoutUnit changeLogicalTop = LayoutUnit::max();
264 LayoutUnit changeLogicalBottom = LayoutUnit::min();
265 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000266 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
267 auto end = floatingObjectSet.end();
268 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000269 const auto& floatingObject = *it->get();
270 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000271 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000272 if (oldFloatingObject) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000273 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
274 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000275 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000276 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000277 } else {
278 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000279 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
280 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000281 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000282 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000283 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000284 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000285 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
286 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000287 }
288 }
289
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000290 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
291 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
292 oldFloatingObject->originatingLine()->markDirty();
293 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000294 } else {
295 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000296 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000297 }
298 }
299 }
300
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000301 auto end = floatMap.end();
302 for (auto it = floatMap.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000303 const auto& floatingObject = *it->value.get();
304 if (!floatingObject.isDescendant()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000305 changeLogicalTop = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000306 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000307 }
308 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000309
310 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
311 } else if (!oldIntrudingFloatSet.isEmpty()) {
312 // If there are previously intruding floats that no longer intrude, then children with floats
313 // should also get layout because they might need their floating object lists cleared.
314 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
315 markAllDescendantsWithFloatsForLayout();
316 else {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000317 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
318 auto end = floatingObjectSet.end();
319 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
320 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000321 if (!oldIntrudingFloatSet.isEmpty())
322 markAllDescendantsWithFloatsForLayout();
323 }
324 }
325}
326
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000327void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
328{
329 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
330 // The min/max intrinsic widths calculated really tell how much space elements need when
331 // laid out inside the columns. In order to eventually end up with the desired column width,
332 // we need to convert them to values pertaining to the multicol container.
333 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
334 LayoutUnit columnWidth;
335 LayoutUnit colGap = columnGap();
336 LayoutUnit gapExtra = (columnCount - 1) * colGap;
337 if (style().hasAutoColumnWidth())
338 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
339 else {
340 columnWidth = style().columnWidth();
341 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
342 }
343 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
344 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
345 // performing a layout pass, but this is not an appropriate time or place for layout. The
346 // good news is that if height is unconstrained and there are no explicit breaks, the
347 // resolved column-count really should be 1.
348 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
349 }
350}
351
352void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
353{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000354 if (childrenInline())
355 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
356 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000357 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
358
359 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
360
361 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
362
363 if (!style().autoWrap() && childrenInline()) {
364 // A horizontal marquee with inline children has no minimum width.
365 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
366 minLogicalWidth = 0;
367 }
368
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000369 if (is<RenderTableCell>(*this)) {
370 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000371 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
372 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
373 }
374
rego@igalia.com76760c72015-05-14 16:37:27 +0000375 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000376 maxLogicalWidth += scrollbarWidth;
377 minLogicalWidth += scrollbarWidth;
378}
379
380bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
381{
382 bool changed = recomputeLogicalWidth();
383
384 LayoutUnit oldColumnWidth = computedColumnWidth();
385 computeColumnCountAndWidth();
386
387 return changed || oldColumnWidth != computedColumnWidth();
388}
389
390LayoutUnit RenderBlockFlow::columnGap() const
391{
392 if (style().hasNormalColumnGap())
393 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
394 return style().columnGap();
395}
396
397void RenderBlockFlow::computeColumnCountAndWidth()
zalan@apple.com748d3822016-12-02 21:25:15 +0000398{
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000399 // Calculate our column width and column count.
400 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
401 unsigned desiredColumnCount = 1;
402 LayoutUnit desiredColumnWidth = contentLogicalWidth();
zalan@apple.com08aaba72016-12-02 23:05:48 +0000403
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000404 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
405 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
406 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
407 return;
408 }
zalan@apple.com08aaba72016-12-02 23:05:48 +0000409
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000410 LayoutUnit availWidth = desiredColumnWidth;
411 LayoutUnit colGap = columnGap();
zalan@apple.com08aaba72016-12-02 23:05:48 +0000412 LayoutUnit colWidth = std::max<LayoutUnit>(1, style().columnWidth());
zalan@apple.com585798f2016-05-18 23:25:47 +0000413 unsigned colCount = std::max<unsigned>(1, style().columnCount());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000414
415 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
416 desiredColumnCount = colCount;
417 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
418 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
zalan@apple.com08aaba72016-12-02 23:05:48 +0000419 desiredColumnCount = std::max<unsigned>(1, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000420 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
421 } else {
zalan@apple.com08aaba72016-12-02 23:05:48 +0000422 desiredColumnCount = std::max<unsigned>(std::min(colCount, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned()), 1);
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000423 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
424 }
425 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
426}
427
zalan@apple.com809f4872016-12-08 18:20:01 +0000428bool RenderBlockFlow::willCreateColumns(std::optional<unsigned> desiredColumnCount) const
zalan@apple.com748d3822016-12-02 21:25:15 +0000429{
zalan@apple.com809f4872016-12-08 18:20:01 +0000430 // The following types are not supposed to create multicol context.
hyatt@apple.com80914862017-03-06 18:00:35 +0000431 if (isFileUploadControl() || isTextControl() || isListBox())
zalan@apple.com809f4872016-12-08 18:20:01 +0000432 return false;
antti@apple.com411949d2017-08-30 17:28:10 +0000433 if (isRenderSVGBlock() || isRenderMathMLBlock() || isRubyRun())
434 return false;
zalan@apple.com809f4872016-12-08 18:20:01 +0000435
zalan@apple.com748d3822016-12-02 21:25:15 +0000436 if (!firstChild())
437 return false;
438
antti@apple.com411949d2017-08-30 17:28:10 +0000439 if (style().styleType() != NOPSEUDO)
440 return false;
441
zalan@apple.com809f4872016-12-08 18:20:01 +0000442 // 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.
443 if ((style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isDocumentElementRenderer() || isBody()))
444 return true;
445
zalan@apple.com748d3822016-12-02 21:25:15 +0000446 if (!style().specifiesColumns())
447 return false;
448
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000449 // column-axis with opposite writing direction initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000450 if (!style().hasInlineColumnAxis())
451 return true;
452
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000453 // Non-auto column-width always initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000454 if (!style().hasAutoColumnWidth())
455 return true;
456
zalan@apple.com809f4872016-12-08 18:20:01 +0000457 if (desiredColumnCount)
458 return desiredColumnCount.value() > 1;
459
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000460 // column-count > 1 always initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000461 if (!style().hasAutoColumnCount())
462 return style().columnCount() > 1;
463
464 ASSERT_NOT_REACHED();
465 return false;
466}
467
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000468void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
469{
470 ASSERT(needsLayout());
471
472 if (!relayoutChildren && simplifiedLayout())
473 return;
474
475 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
476
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000477 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000478 relayoutChildren = true;
479
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000480 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000481
482 LayoutUnit previousHeight = logicalHeight();
483 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
484 // for consistency with other render classes?
485 setLogicalHeight(0);
486
487 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000488 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000489
akling@apple.com827be9c2013-10-29 02:58:43 +0000490 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000491 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000492
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000493 preparePaginationBeforeBlockLayout(relayoutChildren);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000494
495 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
496 // our current maximal positive and negative margins. These values are used when we
497 // are collapsed with adjacent blocks, so for example, if you have block A and B
498 // collapsing together, then you'd take the maximal positive margin from both A and B
499 // and subtract it from the maximal negative margin from both A and B to get the
500 // true collapsed margin. This algorithm is recursive, so when we finish layout()
501 // our block knows its current maximal positive/negative values.
502 //
503 // Start out by setting our margin values to our current margins. Table cells have
504 // no margins, so we don't fill in the values for table cells.
505 bool isCell = isTableCell();
506 if (!isCell) {
507 initMaxMarginValues();
508
akling@apple.com827be9c2013-10-29 02:58:43 +0000509 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
510 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000511 setPaginationStrut(0);
512 }
513
514 LayoutUnit repaintLogicalTop = 0;
515 LayoutUnit repaintLogicalBottom = 0;
516 LayoutUnit maxFloatLogicalBottom = 0;
517 if (!firstChild() && !isAnonymousBlock())
518 setChildrenInline(true);
519 if (childrenInline())
520 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
521 else
522 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
523
524 // Expand our intrinsic height to encompass floats.
525 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000526 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000527 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
528
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000529 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000530 ASSERT(!shouldBreakAtLineToAvoidWidow());
531 return;
532 }
533
534 // Calculate our new height.
535 LayoutUnit oldHeight = logicalHeight();
536 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
537
538 // 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 +0000539 // This ensures the size information is correctly computed for the last auto-height fragment receiving content.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000540 if (is<RenderFragmentedFlow>(*this))
541 downcast<RenderFragmentedFlow>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000542
543 updateLogicalHeight();
544 LayoutUnit newHeight = logicalHeight();
545 if (oldHeight != newHeight) {
546 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
547 // 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 +0000548 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
549 if (blockFlow.isFloatingOrOutOfFlowPositioned())
550 continue;
551 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
552 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000553 }
554 }
555 }
556
557 bool heightChanged = (previousHeight != newHeight);
558 if (heightChanged)
559 relayoutChildren = true;
560
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000561 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000562
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000563 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
564 computeOverflow(oldClientAfterEdge);
565
566 statePusher.pop();
567
568 fitBorderToLinesIfNeeded();
569
570 if (view().layoutState()->m_pageLogicalHeight)
571 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
572
573 updateLayerTransform();
574
575 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
576 // we overflow or not.
577 updateScrollInfoAfterLayout();
578
579 // FIXME: This repaint logic should be moved into a separate helper function!
580 // Repaint with our new bounds if they are different from our old bounds.
581 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000582 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000583 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
584 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
585 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
586 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
587 if (hasOverflowClip()) {
588 // 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.
589 // 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.
590 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000591 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
592 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000593 }
594
595 LayoutRect repaintRect;
596 if (isHorizontalWritingMode())
597 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
598 else
599 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
600
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000601 if (hasOverflowClip()) {
602 // Adjust repaint rect for scroll offset
simon.fraser@apple.com24e03ba2016-05-11 04:48:08 +0000603 repaintRect.moveBy(-scrollPosition());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000604
605 // Don't allow this rect to spill out of our overflow box.
606 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
607 }
608
609 // Make sure the rect is still non-empty after intersecting for overflow above
610 if (!repaintRect.isEmpty()) {
611 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
612 if (hasReflection())
613 repaintRectangle(reflectedRect(repaintRect));
614 }
615 }
616
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000617 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000618}
619
620void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
621{
622 dirtyForLayoutFromPercentageHeightDescendants();
623
624 LayoutUnit beforeEdge = borderAndPaddingBefore();
625 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
626
627 setLogicalHeight(beforeEdge);
628
629 // Lay out our hypothetical grid line as though it occurs at the top of the block.
630 if (view().layoutState()->lineGrid() == this)
631 layoutLineGridBox();
632
633 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000634 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000635
636 // Fieldsets need to find their legend and position it inside the border of the object.
637 // The legend then gets skipped during normal layout. The same is true for ruby text.
638 // It doesn't get included in the normal layout process but is instead skipped.
hyatt@apple.com80914862017-03-06 18:00:35 +0000639 layoutExcludedChildren(relayoutChildren);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000640
641 LayoutUnit previousFloatLogicalBottom = 0;
642 maxFloatLogicalBottom = 0;
643
644 RenderBox* next = firstChildBox();
645
646 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000647 RenderBox& child = *next;
648 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000649
hyatt@apple.com80914862017-03-06 18:00:35 +0000650 if (child.isExcludedFromNormalLayout())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000651 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
652
653 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
654
weinig@apple.com12840dc2013-10-22 23:59:08 +0000655 if (child.isOutOfFlowPositioned()) {
656 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000657 adjustPositionedBlock(child, marginInfo);
658 continue;
659 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000660 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000661 insertFloatingObject(child);
662 adjustFloatingBlock(marginInfo);
663 continue;
664 }
665
666 // Lay out the child.
667 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
668 }
669
670 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
671 // determining the correct collapsed bottom margin information.
672 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
673}
674
antti@apple.com940f5872013-10-24 20:31:11 +0000675void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
676{
akling@apple.coma12fee22015-02-01 02:58:13 +0000677 if (lineLayoutPath() == UndeterminedPath)
678 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000679
akling@apple.coma12fee22015-02-01 02:58:13 +0000680 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000681 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000682 return;
683 }
684
antti@apple.comfea51992013-10-28 13:39:23 +0000685 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000686 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
687}
688
weinig@apple.com12840dc2013-10-22 23:59:08 +0000689void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000690{
691 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
692 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
693
694 // The child is a normal flow object. Compute the margins we will use for collapsing now.
mmaxfield@apple.com09804f42016-03-23 00:58:34 +0000695 child.computeAndSetBlockDirectionMargins(*this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000696
697 // Try to guess our correct logical top position. In most cases this guess will
698 // be correct. Only if we're wrong (when we compute the real logical top position)
699 // will we have to potentially relayout.
700 LayoutUnit estimateWithoutPagination;
701 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
702
703 // 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 +0000704 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000705 LayoutUnit oldLogicalTop = logicalTopForChild(child);
706
707#if !ASSERT_DISABLED
708 LayoutSize oldLayoutDelta = view().layoutDelta();
709#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000710 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000711 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000712 estimateFragmentRangeForBoxChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000713
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000714 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000715 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000716 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000717 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000718 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
719 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
720 // very large elements. If it does the comparison with oldLogicalTop might yield a
721 // false negative as adding and removing margins, borders etc from a saturated number
722 // might yield incorrect results. If this is the case always mark for layout.
723 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000724 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000725 // If an element might be affected by the presence of floats, then always mark it for
726 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000727 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000728 if (fb > logicalTopEstimate)
729 markDescendantsWithFloats = true;
730 }
731
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000732 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000733 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000734 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000735 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000736 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000737 }
738
hyatt@apple.comccad3742015-02-04 21:39:00 +0000739 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000740
weinig@apple.com12840dc2013-10-22 23:59:08 +0000741 bool childHadLayout = child.everHadLayout();
742 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000743 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000744 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000745
746 // Cache if we are at the top of the block right now.
747 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
748
749 // Now determine the correct ypos based off examination of collapsing margin
750 // values.
751 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
752
753 // Now check for clear.
754 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
755
756 bool paginated = view().layoutState()->isPaginated();
757 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000758 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000759
760 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
761
762 // Now we have a final top position. See if it really does end up being different from our estimate.
763 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
764 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000765 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
766 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000767 // The child's width depends on the line width. When the child shifts to clear an item, its width can
768 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000769 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000770 }
771
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000772 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000773 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000774 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000775 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000776 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000777 }
778
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000779 if (updateFragmentRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000780 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000781
782 // In case our guess was wrong, relayout the child.
783 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000784
785 // We are no longer at the top of the block if we encounter a non-empty child.
786 // 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 +0000787 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000788 marginInfo.setAtBeforeSideOfBlock(false);
789
790 // Now place the child in the correct left position
791 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
792
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000793 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000794 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000795 if (mustSeparateMarginAfterForChild(child)) {
796 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
797 marginInfo.clearMargin();
798 }
799 // If the child has overhanging floats that intrude into following siblings (or possibly out
800 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000801 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000802 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000803
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000804 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000805 if (childOffset.width() || childOffset.height()) {
806 view().addLayoutDelta(childOffset);
807
808 // If the child moved, we have to repaint it as well as any floating/positioned
809 // descendants. An exception is if we need a layout. In this case, we know we're going to
810 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000811 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
812 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000813 }
814
weinig@apple.com12840dc2013-10-22 23:59:08 +0000815 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
816 child.repaint();
817 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000818 }
819
820 if (paginated) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000821 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
822 fragmentedFlow->fragmentedFlowDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000823 // Check for an after page/column break.
824 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
825 if (newHeight != height())
826 setLogicalHeight(newHeight);
827 }
828
829 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
830}
831
weinig@apple.com12840dc2013-10-22 23:59:08 +0000832void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000833{
834 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000835 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000836
837 LayoutUnit logicalTop = logicalHeight();
zalan@apple.com4d97a002016-02-24 17:13:33 +0000838 updateStaticInlinePositionForChild(child, logicalTop, DoNotIndentText);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000839
840 if (!marginInfo.canCollapseWithMarginBefore()) {
841 // Positioned blocks don't collapse margins, so add the margin provided by
842 // the container now. The child's own margin is added later when calculating its logical top.
843 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
844 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
845 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
846 }
847
weinig@apple.com12840dc2013-10-22 23:59:08 +0000848 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000849 if (childLayer->staticBlockPosition() != logicalTop) {
850 childLayer->setStaticBlockPosition(logicalTop);
851 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000852 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000853 }
854}
855
robert@webkit.org97037ef2013-11-20 19:26:10 +0000856LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
857{
858 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000859 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000860 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
861 return marginValuesForChild(*this).positiveMarginBefore();
862 return LayoutUnit();
863}
864
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000865void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
866{
867 LayoutUnit startPosition = borderStart() + paddingStart();
mmaxfield@apple.com4195a702016-04-27 01:25:26 +0000868 if (shouldPlaceBlockDirectionScrollbarOnLeft())
mmaxfield@apple.comaf573be2016-03-12 21:18:25 +0000869 startPosition += (style().isLeftToRightDirection() ? 1 : -1) * verticalScrollbarWidth();
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000870 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
871
872 // Add in our start margin.
873 LayoutUnit childMarginStart = marginStartForChild(child);
874 LayoutUnit newPosition = startPosition + childMarginStart;
875
876 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
877 // to shift over as necessary to dodge any floats that might get in the way.
antti@apple.comeae76122017-09-20 15:37:23 +0000878 if (child.avoidsFloats() && containsFloats())
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000879 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
880
881 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
882}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000883
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000884void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
885{
886 // The float should be positioned taking into account the bottom margin
887 // of the previous flow. We add that margin into the height, get the
888 // float positioned properly, and then subtract the margin out of the
889 // height again. In the case of self-collapsing blocks, we always just
890 // use the top margins, since the self-collapsing block collapsed its
891 // own bottom margin into its top margin.
892 //
893 // Note also that the previous flow may collapse its margin into the top of
894 // our block. If this is the case, then we do not add the margin in to our
895 // height when computing the position of the float. This condition can be tested
896 // for by simply calling canCollapseWithMarginBefore. See
897 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
898 // an example of this scenario.
899 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
900 setLogicalHeight(logicalHeight() + marginOffset);
901 positionNewFloats();
902 setLogicalHeight(logicalHeight() - marginOffset);
903}
904
zalan@apple.com4d97a002016-02-24 17:13:33 +0000905void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000906{
akling@apple.com827be9c2013-10-29 02:58:43 +0000907 if (child.style().isOriginalDisplayInlineType())
zalan@apple.com4d97a002016-02-24 17:13:33 +0000908 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, shouldIndentText));
weinig@apple.com12840dc2013-10-22 23:59:08 +0000909 else
910 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
911}
912
913void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
914{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000915 if (enclosingFragmentedFlow()) {
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000916 // Shift the inline position to exclude the fragment offset.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000917 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
918 }
919 child.layer()->setStaticInlinePosition(inlinePosition);
920}
921
922RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000923{
924 LayoutUnit childBeforePositive = 0;
925 LayoutUnit childBeforeNegative = 0;
926 LayoutUnit childAfterPositive = 0;
927 LayoutUnit childAfterNegative = 0;
928
929 LayoutUnit beforeMargin = 0;
930 LayoutUnit afterMargin = 0;
931
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000932 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000933
934 // If the child has the same directionality as we do, then we can just return its
935 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000936 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000937 if (childRenderBlock) {
938 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
939 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
940 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
941 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
942 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000943 beforeMargin = child.marginBefore();
944 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000945 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000946 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000947 // The child has a different directionality. If the child is parallel, then it's just
948 // flipped relative to us. We can use the margins for the opposite edges.
949 if (childRenderBlock) {
950 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
951 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
952 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
953 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
954 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000955 beforeMargin = child.marginAfter();
956 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000957 }
958 } else {
959 // The child is perpendicular to us, which means its margins don't collapse but are on the
960 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
961 beforeMargin = marginBeforeForChild(child);
962 afterMargin = marginAfterForChild(child);
963 }
964
965 // Resolve uncollapsing margins into their positive/negative buckets.
966 if (beforeMargin) {
967 if (beforeMargin > 0)
968 childBeforePositive = beforeMargin;
969 else
970 childBeforeNegative = -beforeMargin;
971 }
972 if (afterMargin) {
973 if (afterMargin > 0)
974 childAfterPositive = afterMargin;
975 else
976 childAfterNegative = -afterMargin;
977 }
978
979 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
980}
981
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000982bool RenderBlockFlow::childrenPreventSelfCollapsing() const
983{
984 if (!childrenInline())
985 return RenderBlock::childrenPreventSelfCollapsing();
986
antti@apple.comae85e112017-08-31 23:27:02 +0000987 return hasLines();
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000988}
989
weinig@apple.com12840dc2013-10-22 23:59:08 +0000990LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000991{
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000992 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
993}
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000994
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000995LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
996{
997 bool childDiscardMarginBefore = child ? mustDiscardMarginBeforeForChild(*child) : false;
998 bool childDiscardMarginAfter = child ? mustDiscardMarginAfterForChild(*child) : false;
999 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
1000 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
1001 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
1002
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001003 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
1004 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001005
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001006 // Get the four margin values for the child and cache them.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001007 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001008
1009 // Get our max pos and neg top margins.
1010 LayoutUnit posTop = childMargins.positiveMarginBefore();
1011 LayoutUnit negTop = childMargins.negativeMarginBefore();
1012
1013 // For self-collapsing blocks, collapse our bottom margins into our
1014 // top to get new posTop and negTop values.
1015 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +00001016 posTop = std::max(posTop, childMargins.positiveMarginAfter());
1017 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001018 }
1019
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001020 if (marginInfo.canCollapseWithMarginBefore()) {
1021 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1022 // This child is collapsing with the top of the
1023 // block. If it has larger margin values, then we need to update
1024 // our own maximal values.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001025 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +00001026 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001027
1028 // The minute any of the margins involved isn't a quirk, don't
1029 // collapse it away, even if the margin is smaller (www.webreference.com
1030 // has an example of this, a <dt> with 0.8em author-specified inside
1031 // a <dl> inside a <td>.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001032 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001033 setHasMarginBeforeQuirk(false);
1034 marginInfo.setDeterminedMarginBeforeQuirk(true);
1035 }
1036
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001037 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001038 // We have no top margin and our top child has a quirky margin.
1039 // We will pick up this quirky margin and pass it through.
1040 // This deals with the <td><div><p> case.
1041 // Don't do this for a block that split two inlines though. You do
1042 // still apply margins in this case.
1043 setHasMarginBeforeQuirk(true);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001044 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001045 } else
1046 // The before margin of the container will also discard all the margins it is collapsing with.
1047 setMustDiscardMarginBefore();
1048 }
1049
1050 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1051 if (childDiscardMarginBefore) {
1052 marginInfo.setDiscardMargin(true);
1053 marginInfo.clearMargin();
1054 }
1055
1056 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001057 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001058
1059 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1060 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001061
1062 LayoutUnit clearanceForSelfCollapsingBlock;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001063
robert@webkit.org97037ef2013-11-20 19:26:10 +00001064 // 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
1065 // 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
1066 // 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 +00001067 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1068 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001069 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1070 }
1071
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001072 if (childIsSelfCollapsing) {
1073 // 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.
1074 // Also, the child's top position equals the logical height of the container.
1075 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1076 // This child has no height. We need to compute our
1077 // position before we collapse the child's margins together,
1078 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001079 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1080 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001081 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1082
1083 // Now collapse the child's margins together, which means examining our
1084 // bottom margin values as well.
1085 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1086 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1087
1088 if (!marginInfo.canCollapseWithMarginBefore())
1089 // We need to make sure that the position of the self-collapsing block
1090 // is correct, since it could have overflowing content
1091 // that needs to be positioned correctly (e.g., a block that
1092 // had a specified height of 0 but that actually had subcontent).
1093 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1094 }
1095 } else {
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001096 if (child && mustSeparateMarginBeforeForChild(*child)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001097 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1098 // If we are at the before side of the block and we collapse, ignore the computed margin
1099 // and just add the child margin to the container height. This will correctly position
1100 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001101 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001102 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(*child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001103 logicalTop = logicalHeight();
1104 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1105 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1106 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1107 // We're collapsing with a previous sibling's margins and not
1108 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001109 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001110 logicalTop = logicalHeight();
1111 }
1112
1113 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1114
1115 if (!marginInfo.discardMargin()) {
1116 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1117 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1118 } else
1119 marginInfo.clearMargin();
1120
1121 if (marginInfo.margin())
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001122 marginInfo.setHasMarginAfterQuirk(afterQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001123 }
1124
1125 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1126 // collapsed into the page edge.
1127 LayoutState* layoutState = view().layoutState();
1128 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1129 && hasNextPage(beforeCollapseLogicalTop)) {
1130 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001131 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001132 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1133 }
1134
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001135 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001136 // 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
1137 // any floats from the parent will now overhang.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001138 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001139 LayoutUnit oldLogicalHeight = logicalHeight();
1140 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001141 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001142 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001143 setLogicalHeight(oldLogicalHeight);
1144
1145 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1146 // 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
1147 // floats in the parent that overhang |child|'s new logical top.
1148 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001149 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1150 child->setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001151 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001152
1153 return logicalTop;
1154}
1155
weinig@apple.com12840dc2013-10-22 23:59:08 +00001156LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001157{
1158 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1159 if (!heightIncrease)
1160 return yPos;
1161
weinig@apple.com12840dc2013-10-22 23:59:08 +00001162 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001163 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1164
1165 // For self-collapsing blocks that clear, they can still collapse their
1166 // margins with following siblings. Reset the current margins to represent
1167 // the self-collapsing block's margins only.
1168 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001169 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001170 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001171 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1172 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001173 } else
1174 marginInfo.clearMargin();
1175 marginInfo.setDiscardMargin(childDiscardMargin);
1176
1177 // CSS2.1 states:
1178 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1179 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1180 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1181 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1182 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001183 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001184 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1185 wouldCollapseMarginsWithParent = false;
1186 }
1187 if (wouldCollapseMarginsWithParent)
1188 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1189
robert@webkit.org97037ef2013-11-20 19:26:10 +00001190 // 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
1191 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1192 // 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
1193 // margins can collapse at the correct vertical position.
1194 // 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
1195 // (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],
1196 // i.e., clearance = [height of float] - margin-top".
1197 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001198 } else
1199 // Increase our height by the amount we had to clear.
1200 setLogicalHeight(logicalHeight() + heightIncrease);
1201
1202 if (marginInfo.canCollapseWithMarginBefore()) {
1203 // We can no longer collapse with the top of the block since a clear
1204 // occurred. The empty blocks collapse into the cleared block.
1205 // FIXME: This isn't quite correct. Need clarification for what to do
1206 // if the height the cleared block is offset by is smaller than the
1207 // margins involved.
1208 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1209 marginInfo.setAtBeforeSideOfBlock(false);
1210
1211 // 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 +00001212 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001213 }
1214
robert@webkit.org97037ef2013-11-20 19:26:10 +00001215 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001216}
1217
weinig@apple.com12840dc2013-10-22 23:59:08 +00001218void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001219{
1220 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1221 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1222 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001223 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001224 return;
1225
1226 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1227 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001228 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001229 positiveMarginBefore = 0;
1230 negativeMarginBefore = 0;
1231 discardMarginBefore = true;
1232 return;
1233 }
1234
1235 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001236 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1237 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001238
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001239 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001240 return;
1241
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001242 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001243 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001244 return;
1245
weinig@apple.com12840dc2013-10-22 23:59:08 +00001246 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001247 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1248 return;
1249
weinig@apple.com12840dc2013-10-22 23:59:08 +00001250 RenderBox* grandchildBox = childBlock.firstChildBox();
1251 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001252 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1253 break;
1254 }
1255
1256 // 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 +00001257 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001258 return;
1259
1260 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1261 if (grandchildBox->needsLayout()) {
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00001262 grandchildBox->computeAndSetBlockDirectionMargins(*this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001263 if (is<RenderBlock>(*grandchildBox)) {
1264 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1265 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1266 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001267 }
1268 }
1269
1270 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001271 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001272}
1273
weinig@apple.com12840dc2013-10-22 23:59:08 +00001274LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001275{
1276 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1277 // relayout if there are intruding floats.
1278 LayoutUnit logicalTopEstimate = logicalHeight();
1279 if (!marginInfo.canCollapseWithMarginBefore()) {
1280 LayoutUnit positiveMarginBefore = 0;
1281 LayoutUnit negativeMarginBefore = 0;
1282 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001283 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001284 // Try to do a basic estimation of how the collapse is going to go.
1285 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1286 } else {
1287 // Use the cached collapsed margin values from a previous layout. Most of the time they
1288 // will be right.
1289 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001290 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1291 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001292 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1293 }
1294
1295 // Collapse the result with our current margins.
1296 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001297 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001298 }
1299
1300 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1301 // page.
1302 LayoutState* layoutState = view().layoutState();
1303 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1304 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001305 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001306
1307 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1308
1309 estimateWithoutPagination = logicalTopEstimate;
1310
1311 if (layoutState->isPaginated()) {
1312 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1313 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1314
1315 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1316 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1317
cdumez@apple.come9437792014-10-08 23:33:43 +00001318 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1319 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001320 }
1321
1322 return logicalTopEstimate;
1323}
1324
1325void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1326{
1327 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1328 // 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.
1329 // Don't update the max margin values because we won't need them anyway.
1330 if (marginInfo.discardMargin()) {
1331 setMustDiscardMarginAfter();
1332 return;
1333 }
1334
1335 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1336 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001337 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001338
1339 if (!marginInfo.hasMarginAfterQuirk())
1340 setHasMarginAfterQuirk(false);
1341
1342 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1343 // We have no bottom margin and our last child has a quirky margin.
1344 // We will pick up this quirky margin and pass it through.
1345 // This deals with the <td><div><p> case.
1346 setHasMarginAfterQuirk(true);
1347 }
1348}
1349
1350void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1351{
1352 marginInfo.setAtAfterSideOfBlock(true);
1353
robert@webkit.org97037ef2013-11-20 19:26:10 +00001354 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1355 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1356 // to perform now is at the child's margin-top - so adjust our height to that position.
1357 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001358 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1359 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001360
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001361 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001362 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1363 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1364 setLogicalHeight(logicalHeight() + marginInfo.margin());
1365
1366 // Now add in our bottom border/padding.
1367 setLogicalHeight(logicalHeight() + afterSide);
1368
1369 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1370 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001371 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001372
1373 // Update our bottom collapsed margin info.
1374 setCollapsedBottomMargin(marginInfo);
1375}
1376
1377void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1378{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001379 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001380 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001381 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001382 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001383 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001384
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001385 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1386 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001387}
1388
1389void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1390{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001391 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001392 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001393 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001394 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001395 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001396
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001397 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1398 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001399}
1400
1401void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1402{
akling@apple.com827be9c2013-10-29 02:58:43 +00001403 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001404 ASSERT(value);
1405 return;
1406 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001407
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001408 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001409 if (!value)
1410 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001411 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001412 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001413
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001414 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001415}
1416
1417void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1418{
akling@apple.com827be9c2013-10-29 02:58:43 +00001419 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001420 ASSERT(value);
1421 return;
1422 }
1423
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001424 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001425 if (!value)
1426 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001427 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001428 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001429
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001430 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001431}
1432
1433bool RenderBlockFlow::mustDiscardMarginBefore() const
1434{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001435 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001436}
1437
1438bool RenderBlockFlow::mustDiscardMarginAfter() const
1439{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001440 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001441}
1442
weinig@apple.com12840dc2013-10-22 23:59:08 +00001443bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001444{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001445 ASSERT(!child.selfNeedsLayout());
1446 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001447 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001448 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001449 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001450
1451 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1452 // In case the boxes are perpendicular we assume the property is not specified.
1453 return false;
1454}
1455
weinig@apple.com12840dc2013-10-22 23:59:08 +00001456bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001457{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001458 ASSERT(!child.selfNeedsLayout());
1459 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001460 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001461 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001462 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001463
1464 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1465 return false;
1466}
1467
weinig@apple.com12840dc2013-10-22 23:59:08 +00001468bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001469{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001470 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001471 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001472 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001473 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001474 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001475 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001476
1477 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1478 return false;
1479}
1480
weinig@apple.com12840dc2013-10-22 23:59:08 +00001481bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001482{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001483 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001484 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001485 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001486 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001487 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001488 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001489
1490 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1491 return false;
1492}
1493
weinig@apple.com12840dc2013-10-22 23:59:08 +00001494static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001495{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001496 RenderBlock* curr = child.containingBlock();
1497 while (curr && curr != &child.view()) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001498 if (curr->isRenderFragmentedFlow())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001499 return true;
1500 if (curr->isFloatingOrOutOfFlowPositioned())
1501 return false;
1502 curr = curr->containingBlock();
1503 }
1504 return true;
1505}
1506
weinig@apple.com12840dc2013-10-22 23:59:08 +00001507LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001508{
1509 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001510 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1511 bool isInsideMulticolFlow = fragmentedFlow;
1512 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001513 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 +00001514 bool checkFragmentBreaks = false;
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001515 bool checkBeforeAlways = (checkColumnBreaks && child.style().breakBefore() == ColumnBreakBetween)
antti@apple.com52d83832017-09-20 12:58:45 +00001516 || (checkPageBreaks && alwaysPageBreak(child.style().breakBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001517 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001518 if (checkColumnBreaks) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001519 if (isInsideMulticolFlow)
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001520 checkFragmentBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001521 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001522 if (checkFragmentBreaks) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001523 LayoutUnit offsetBreakAdjustment = 0;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001524 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001525 return logicalOffset + offsetBreakAdjustment;
1526 }
1527 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1528 }
1529 return logicalOffset;
1530}
1531
weinig@apple.com12840dc2013-10-22 23:59:08 +00001532LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001533{
1534 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001535 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1536 bool isInsideMulticolFlow = fragmentedFlow;
1537 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001538 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 +00001539 bool checkFragmentBreaks = false;
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001540 bool checkAfterAlways = (checkColumnBreaks && child.style().breakAfter() == ColumnBreakBetween)
antti@apple.com52d83832017-09-20 12:58:45 +00001541 || (checkPageBreaks && alwaysPageBreak(child.style().breakAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001542 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1543 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1544
1545 // So our margin doesn't participate in the next collapsing steps.
1546 marginInfo.clearMargin();
1547
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001548 if (checkColumnBreaks) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001549 if (isInsideMulticolFlow)
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001550 checkFragmentBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001551 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001552 if (checkFragmentBreaks) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001553 LayoutUnit offsetBreakAdjustment = 0;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001554 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001555 return logicalOffset + marginOffset + offsetBreakAdjustment;
1556 }
1557 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1558 }
1559 return logicalOffset;
1560}
1561
weinig@apple.com12840dc2013-10-22 23:59:08 +00001562LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001563{
cdumez@apple.come9437792014-10-08 23:33:43 +00001564 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001565
1566 if (estimateWithoutPagination != logicalTopAfterClear) {
1567 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1568 // position.
1569 setLogicalHeight(logicalTopAfterClear);
1570 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1571
weinig@apple.com12840dc2013-10-22 23:59:08 +00001572 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001573 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1574 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001575 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001576 }
1577
1578 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001579 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001580 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001581 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001582 }
1583
1584 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001585 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001586 }
1587
1588 LayoutUnit oldTop = logicalTopAfterClear;
1589
1590 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1591 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1592
1593 if (pageLogicalHeightForOffset(result)) {
1594 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001595 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001596 if (spaceShortage > 0) {
1597 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1598 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1599 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1600 // This should be improved, though, because here we just pretend that the child is
1601 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1602 // where there's no child content, border or padding. In other words, we risk stretching more
1603 // than necessary.
1604 setPageBreak(result, spaceShortage);
1605 }
1606 }
1607
1608 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1609 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1610 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1611
1612 LayoutUnit paginationStrut = 0;
1613 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1614 if (unsplittableAdjustmentDelta)
1615 paginationStrut = unsplittableAdjustmentDelta;
1616 else if (childRenderBlock && childRenderBlock->paginationStrut())
1617 paginationStrut = childRenderBlock->paginationStrut();
1618
1619 if (paginationStrut) {
1620 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1621 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1622 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1623 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1624 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1625 // and pushes to the next page anyway, so not too concerned about it.
1626 setPaginationStrut(result + paginationStrut);
1627 if (childRenderBlock)
1628 childRenderBlock->setPaginationStrut(0);
1629 } else
1630 result += paginationStrut;
1631 }
1632
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001633 // 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 +00001634 setLogicalHeight(logicalHeight() + (result - oldTop));
1635
1636 // Return the final adjusted logical top.
1637 return result;
1638}
1639
antti@apple.com5c4302b2016-04-26 18:20:09 +00001640static inline LayoutUnit calculateMinimumPageHeight(const RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001641{
1642 // We may require a certain minimum number of lines per page in order to satisfy
1643 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001644 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001645 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001646 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001647 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1648 line = line->prevRootBox();
1649
1650 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1651 // adjustLinePositionForPagination() for more details.
1652 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001653 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001654 }
1655 return lineBottom - lineTop;
1656}
1657
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001658static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1659{
zalan@apple.coma1cff3a2017-01-14 18:45:20 +00001660 auto& renderer = lineBox.renderer();
bfulgham@apple.com62729772015-04-29 02:26:07 +00001661
zalan@apple.coma1cff3a2017-01-14 18:45:20 +00001662 if (!renderer.settings().appleMailPaginationQuirkEnabled())
bfulgham@apple.com62729772015-04-29 02:26:07 +00001663 return false;
1664
cdumez@apple.combee81ac2016-04-21 23:28:48 +00001665 if (renderer.element() && renderer.element()->idForStyleResolution() == "messageContentContainer")
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001666 return true;
1667
1668 return false;
1669}
zalan@apple.come031dfb2016-08-25 18:41:22 +00001670
1671static void clearShouldBreakAtLineToAvoidWidowIfNeeded(RenderBlockFlow& blockFlow)
1672{
1673 if (!blockFlow.shouldBreakAtLineToAvoidWidow())
1674 return;
1675 blockFlow.clearShouldBreakAtLineToAvoidWidow();
1676 blockFlow.setDidBreakAtLineToAvoidWidow();
1677}
1678
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001679void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsFragment, RenderFragmentedFlow* fragmentedFlow)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001680{
1681 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1682 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1683 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1684 // of the first column.
1685 //
1686 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1687 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1688 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1689 // for overflow to occur), and then cache visible overflow for each column rect.
1690 //
1691 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1692 // content that paints in a previous column (and content that paints in the following column).
1693 //
1694 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1695 // at least make positive leading work in typical cases.
1696 //
1697 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1698 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1699 // line and all following lines.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001700 overflowsFragment = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001701 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001702 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1703 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001704 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001705 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001706 logicalOffset += delta;
1707 lineBox->setPaginationStrut(0);
1708 lineBox->setIsFirstAfterPageBreak(false);
1709 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001710 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001711 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1712 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001713 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001714 // 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.
1715 // 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 +00001716 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001717 }
1718
1719 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1720 // 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
1721 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1722 // 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
1723 // top of the page.
1724 // 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
1725 // this will be a real-world issue. For now we don't try to deal with this problem.
1726 logicalOffset = intMaxForLayoutUnit;
1727 logicalBottom = intMinForLayoutUnit;
1728 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1729 lineHeight = logicalBottom - logicalOffset;
zalan@apple.come031dfb2016-08-25 18:41:22 +00001730 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) {
1731 // Give up. We're genuinely too big even after excluding blank space and overflow.
1732 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
1733 return;
1734 }
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001735 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1736 }
1737
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001738 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001739 overflowsFragment = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001740
1741 int lineIndex = lineCount(lineBox);
1742 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
zalan@apple.come031dfb2016-08-25 18:41:22 +00001743 if (lineBreakToAvoidWidow() == lineIndex)
1744 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001745 // If we have a non-uniform page height, then we have to shift further possibly.
1746 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1747 return;
1748 if (lineHeight > pageLogicalHeight) {
1749 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001750 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001751 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001752 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001753 overflowsFragment = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001754 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001755 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1756 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001757 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001758 && !isOutOfFlowPositioned() && !isTableCell()) {
1759 auto firstRootBox = this->firstRootBox();
1760 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1761 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001762 if (needsAppleMailPaginationQuirk(*lineBox))
1763 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001764 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1765 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001766 delta += remainingLogicalHeight;
1767 lineBox->setPaginationStrut(remainingLogicalHeight);
1768 lineBox->setIsFirstAfterPageBreak(true);
1769 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001770 } else if (remainingLogicalHeight == pageLogicalHeight) {
1771 // We're at the very top of a page or column.
1772 if (lineBox != firstRootBox())
1773 lineBox->setIsFirstAfterPageBreak(true);
1774 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1775 setPageBreak(logicalOffset, lineHeight);
1776 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001777}
1778
1779void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1780{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001781 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001782 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1783 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001784}
1785
abucur@adobe.comfc497132013-10-04 08:49:21 +00001786void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1787{
1788 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001789 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001790 return;
1791
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001792 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001793}
1794
1795void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1796{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001797 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001798 return;
1799
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001800 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001801}
1802
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001803void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1804{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001805 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001806 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001807 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001808
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001809 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001810}
1811
1812bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1813{
1814 if (!shouldBreakAtLineToAvoidWidow())
1815 return false;
1816
1817 statePusher.pop();
1818 setEverHadLayout(true);
1819 layoutBlock(false);
1820 return true;
1821}
1822
weinig@apple.com31324fd2013-10-28 19:22:51 +00001823bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1824{
1825 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1826
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001827 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1828 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001829 return true; // Printing and multi-column both make new pages to accommodate content.
1830
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001831 // See if we're in the last fragment.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001832 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001833 RenderFragmentContainer* fragment = fragmentedFlow->fragmentAtBlockOffset(this, pageOffset, true);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001834 if (!fragment)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001835 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001836
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001837 if (fragment->isLastFragment())
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001838 return fragment->isRenderFragmentContainerSet() || (pageBoundaryRule == IncludePageBoundary && pageOffset == fragment->logicalTopForFragmentedFlowContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001839
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001840 RenderFragmentContainer* startFragment = nullptr;
1841 RenderFragmentContainer* endFragment = nullptr;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001842 fragmentedFlow->getFragmentRangeForBox(this, startFragment, endFragment);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001843 return (endFragment && fragment != endFragment);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001844}
1845
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001846LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, LayoutUnit childBeforeMargin, LayoutUnit childAfterMargin)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001847{
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001848 // When flexboxes are embedded inside a block flow, they don't perform any adjustments for unsplittable
1849 // children. We'll treat flexboxes themselves as unsplittable just to get them to paginate properly inside
1850 // a block flow.
1851 bool isUnsplittable = childBoxIsUnsplittableForFragmentation(child);
1852 if (!isUnsplittable && !(child.isFlexibleBox() && !downcast<RenderFlexibleBox>(child).isFlexibleBoxImpl()))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001853 return logicalOffset;
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001854
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001855 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001856 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + childBeforeMargin + childAfterMargin;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001857 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001858 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001859 if (isUnsplittable)
1860 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001861 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1862 || !hasNextPage(logicalOffset))
1863 return logicalOffset;
1864 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1865 if (remainingLogicalHeight < childLogicalHeight) {
1866 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1867 return logicalOffset;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001868 auto result = logicalOffset + remainingLogicalHeight;
1869 bool isInitialLetter = child.isFloating() && child.style().styleType() == FIRST_LETTER && child.style().initialLetterDrop() > 0;
1870 if (isInitialLetter) {
1871 // Increase our logical height to ensure that lines all get pushed along with the letter.
1872 setLogicalHeight(logicalOffset + remainingLogicalHeight);
1873 }
1874 return result;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001875 }
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001876
weinig@apple.com31324fd2013-10-28 19:22:51 +00001877 return logicalOffset;
1878}
1879
1880bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1881{
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001882 bool checkFragment = false;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001883 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1884 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1885 if (minimumLogicalHeight <= pageLogicalHeight)
1886 return true;
1887 if (!hasNextPage(logicalOffset + adjustment))
1888 return false;
1889 adjustment += pageLogicalHeight;
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001890 checkFragment = true;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001891 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001892 return !checkFragment;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001893}
1894
1895void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1896{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001897 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1898 fragmentedFlow->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001899}
1900
1901void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1902{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001903 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1904 fragmentedFlow->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001905}
1906
1907LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1908{
1909 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1910 if (!pageLogicalHeight)
1911 return logicalOffset;
1912
1913 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1914 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1915 if (pageBoundaryRule == ExcludePageBoundary)
1916 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1917 return logicalOffset + remainingLogicalHeight;
1918}
1919
1920LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1921{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001922 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1923 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1924 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1925 if (!pageLogicalHeight)
1926 return 0;
1927
weinig@apple.com31324fd2013-10-28 19:22:51 +00001928 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1929 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1930
1931 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001932 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1933 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001934 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001935 return firstPageLogicalTop + fragmentedFlow->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001936}
1937
1938LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1939{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001940 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1941 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1942 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1943 if (!pageLogicalHeight)
1944 return 0;
1945
1946 // Now check for a flow thread.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001947 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1948 if (!fragmentedFlow)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001949 return pageLogicalHeight;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001950 return fragmentedFlow->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
weinig@apple.com31324fd2013-10-28 19:22:51 +00001951}
1952
1953LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1954{
1955 offset += offsetFromLogicalTopOfFirstPage();
1956
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001957 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1958 if (!fragmentedFlow) {
weinig@apple.com31324fd2013-10-28 19:22:51 +00001959 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1960 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1961 if (pageBoundaryRule == IncludePageBoundary) {
1962 // If includeBoundaryPoint is true the line exactly on the top edge of a
1963 // column will act as being part of the previous column.
1964 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1965 }
1966 return remainingHeight;
1967 }
1968
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001969 return fragmentedFlow->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001970}
1971
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001972LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1973{
antti@apple.comeae76122017-09-20 15:37:23 +00001974 return logicalHeightForChild(child);
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001975}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001976
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001977void RenderBlockFlow::layoutLineGridBox()
1978{
akling@apple.com827be9c2013-10-29 02:58:43 +00001979 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001980 setLineGridBox(0);
1981 return;
1982 }
1983
1984 setLineGridBox(0);
1985
akling@apple.com1aa97b02013-10-31 21:59:49 +00001986 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001987 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1988 lineGridBox->setConstructed();
1989 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1990 VerticalPositionCache verticalPositionCache;
1991 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1992
aestes@apple.com13aae082016-01-02 08:03:08 +00001993 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001994
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001995 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1996 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1997 // to this grid.
1998}
1999
weinig@apple.com12840dc2013-10-22 23:59:08 +00002000bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002001{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002002 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002003}
2004
2005void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
2006{
2007 RenderBlock::styleDidChange(diff, oldStyle);
2008
2009 // After our style changed, if we lose our ability to propagate floats into next sibling
2010 // blocks, then we need to find the top most parent containing that overhanging float and
2011 // then mark its descendants with floats for layout and clear all floats from its next
2012 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
2013 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
2014 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2015 RenderBlockFlow* parentBlock = this;
2016 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002017
weinig@apple.comc77041e2013-12-14 18:05:45 +00002018 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2019 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00002020 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00002021 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002022 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2023 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002024 if (ancestor.hasOverhangingFloat(renderer)) {
2025 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002026 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002027 }
2028 }
2029 }
2030 }
2031
2032 parentBlock->markAllDescendantsWithFloatsForLayout();
2033 parentBlock->markSiblingsWithFloatsForLayout();
2034 }
zalan@apple.com07a1ebc2017-03-16 01:56:57 +00002035 // Fresh floats need to be reparented if they actually belong to the previous anonymous block.
2036 // It copies the logic of RenderBlock::addChildIgnoringContinuation
2037 if (noLongerAffectsParentBlock() && style().isFloating() && previousSibling() && previousSibling()->isAnonymousBlock())
2038 downcast<RenderBoxModelObject>(*parent()).moveChildTo(&downcast<RenderBoxModelObject>(*previousSibling()), this);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002039
antti@apple.com9e891c82014-05-22 06:12:34 +00002040 if (diff >= StyleDifferenceRepaint) {
2041 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2042 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2043 invalidateLineLayoutPath();
2044 }
2045
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002046 if (multiColumnFlow())
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002047 updateStylesForColumnChildren();
2048}
2049
2050void RenderBlockFlow::updateStylesForColumnChildren()
2051{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002052 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFragmentedFlow() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
antti@apple.com454418f2016-04-25 19:49:23 +00002053 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002054}
2055
akling@apple.combdae43242013-10-25 12:00:20 +00002056void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002057{
akling@apple.com827be9c2013-10-29 02:58:43 +00002058 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002059 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2060
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002061 if (oldStyle) {
2062 EPosition oldPosition = oldStyle->position();
2063 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002064
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002065 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2066 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2067 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002068 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002069 }
2070
2071 RenderBlock::styleWillChange(diff, newStyle);
2072}
2073
antti@apple.coma2c7f242013-10-22 22:37:25 +00002074void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002075{
2076 if (containsFloats())
2077 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002078
antti@apple.comfea51992013-10-28 13:39:23 +00002079 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002080 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002081 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002082 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002083 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002084
antti@apple.coma2c7f242013-10-22 22:37:25 +00002085 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002086}
2087
zalan@apple.com232b0932016-12-24 18:00:00 +00002088void RenderBlockFlow::addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002089{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002090 // When a portion of the render tree is being detached, anonymous blocks
2091 // will be combined as their children are deleted. In this process, the
2092 // anonymous block later in the tree is merged into the one preceeding it.
2093 // It can happen that the later block (this) contains floats that the
2094 // previous block (toBlockFlow) did not contain, and thus are not in the
2095 // floating objects list for toBlockFlow. This can result in toBlockFlow
2096 // containing floats that are not in it's floating objects list, but are in
2097 // the floating objects lists of siblings and parents. This can cause
2098 // problems when the float itself is deleted, since the deletion code
2099 // assumes that if a float is not in it's containing block's floating
2100 // objects list, it isn't in any floating objects list. In order to
2101 // preserve this condition (removing it has serious performance
2102 // implications), we need to copy the floating objects from the old block
2103 // (this) to the new block (toBlockFlow). The float's metrics will likely
2104 // all be wrong, but since toBlockFlow is already marked for layout, this
2105 // will get fixed before anything gets displayed.
2106 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
zalan@apple.com232b0932016-12-24 18:00:00 +00002107 if (!m_floatingObjects)
2108 return;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002109
zalan@apple.com232b0932016-12-24 18:00:00 +00002110 if (!toBlockFlow.m_floatingObjects)
2111 toBlockFlow.createFloatingObjects();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002112
zalan@apple.com26018542017-03-30 01:25:00 +00002113 for (auto& floatingObject : m_floatingObjects->set()) {
2114 if (toBlockFlow.containsFloat(floatingObject->renderer()))
2115 continue;
zalan@apple.com232b0932016-12-24 18:00:00 +00002116 toBlockFlow.m_floatingObjects->add(floatingObject->cloneForNewParent());
zalan@apple.com26018542017-03-30 01:25:00 +00002117 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002118}
2119
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002120void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002121{
zalan@apple.com232b0932016-12-24 18:00:00 +00002122 auto& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002123 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
zalan@apple.com232b0932016-12-24 18:00:00 +00002124 addFloatsToNewParent(toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002125}
2126
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002127void RenderBlockFlow::addOverflowFromFloats()
2128{
2129 if (!m_floatingObjects)
2130 return;
2131
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002132 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2133 auto end = floatingObjectSet.end();
2134 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002135 const auto& floatingObject = *it->get();
2136 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002137 addOverflowFromChild(&floatingObject.renderer(), floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002138 }
2139}
2140
2141void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2142{
2143 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2144
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002145 if (!multiColumnFlow() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002146 addOverflowFromFloats();
2147}
2148
2149void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2150{
2151 // Repaint any overhanging floats (if we know we're the one to paint them).
2152 // Otherwise, bail out.
2153 if (!hasOverhangingFloats())
2154 return;
2155
2156 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2157 // in this block. Better yet would be to push extra state for the containers of other floats.
zalan@apple.com163bc1c2015-08-12 03:41:40 +00002158 LayoutStateDisabler layoutStateDisabler(view());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002159 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2160 auto end = floatingObjectSet.end();
2161 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002162 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002163 // Only repaint the object if it is overhanging, is not in its own layer, and
2164 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2165 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002166 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002167 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002168 && !renderer.hasSelfPaintingLayer()
2169 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2170 renderer.repaint();
2171 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002172 }
2173 }
2174}
2175
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002176void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002177{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002178 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002179
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002180 if (!multiColumnFlow() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002181 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002182
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002183 // Iterate over our children and paint the column rules as needed.
2184 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2185 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2186 columnSet.paintColumnRules(paintInfo, childPoint);
2187 }
2188}
2189
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002190void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2191{
2192 if (!m_floatingObjects)
2193 return;
2194
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002195 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2196 auto end = floatingObjectSet.end();
2197 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002198 const auto& floatingObject = *it->get();
2199 auto& renderer = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002200 // Only paint the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002201 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002202 PaintInfo currentPaintInfo(paintInfo);
2203 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002204 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, paintOffset + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002205 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002206 if (!preservePhase) {
2207 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002208 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002209 currentPaintInfo.phase = PaintPhaseFloat;
zalan@apple.com6816b132015-10-17 19:14:53 +00002210 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002211 currentPaintInfo.phase = PaintPhaseForeground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002212 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002213 currentPaintInfo.phase = PaintPhaseOutline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002214 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002215 }
2216 }
2217 }
2218}
2219
weinig@apple.com12840dc2013-10-22 23:59:08 +00002220void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002221{
2222 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002223 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2224 auto end = floatingObjectSet.end();
2225 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002226 const auto& floatingObject = *it->get();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002227 LayoutRect floatBox(offsetFromRootBlock.width(), offsetFromRootBlock.height(), floatingObject.renderer().width(), floatingObject.renderer().height());
2228 floatBox.move(floatingObject.locationOffsetOfBorderBox());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002229 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002230 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002231 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002232 }
2233 }
2234}
2235
2236void RenderBlockFlow::createFloatingObjects()
2237{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002238 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002239}
2240
2241void RenderBlockFlow::removeFloatingObjects()
2242{
2243 if (!m_floatingObjects)
2244 return;
2245
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002246 markSiblingsWithFloatsForLayout();
2247
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002248 m_floatingObjects->clear();
2249}
2250
weinig@apple.com12840dc2013-10-22 23:59:08 +00002251FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002252{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002253 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002254
2255 // Create the list of special objects if we don't aleady have one
2256 if (!m_floatingObjects)
2257 createFloatingObjects();
2258 else {
2259 // Don't insert the floatingObject again if it's already in the list
2260 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002261 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002262 if (it != floatingObjectSet.end())
2263 return it->get();
2264 }
2265
2266 // Create the special floatingObject entry & append it to the list
2267
weinig@apple.com12840dc2013-10-22 23:59:08 +00002268 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002269
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002270 // 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 +00002271 bool isChildRenderBlock = floatBox.isRenderBlock();
2272 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2273 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002274
2275 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002276 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2277 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002278 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002279 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2280 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002281 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002282 floatBox.updateLogicalWidth();
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00002283 floatBox.computeAndSetBlockDirectionMargins(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002284 }
2285
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002286 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002287
aestes@apple.com13aae082016-01-02 08:03:08 +00002288 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002289}
2290
weinig@apple.com12840dc2013-10-22 23:59:08 +00002291void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002292{
2293 if (m_floatingObjects) {
2294 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002295 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002296 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002297 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002298 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002299 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2300 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002301
2302 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2303 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2304 logicalBottom = LayoutUnit::max();
2305 else {
2306 // Special-case zero- and less-than-zero-height floats: those don't touch
2307 // the line that they're on, but it still needs to be dirtied. This is
2308 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002309 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002310 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002311 if (floatingObject.originatingLine()) {
2312 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002313 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002314 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2315 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002316 }
2317#if !ASSERT_DISABLED
zalan@apple.comd2acead2017-09-20 22:03:06 +00002318 floatingObject.clearOriginatingLine();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002319#endif
2320 }
2321 markLinesDirtyInBlockRange(0, logicalBottom);
2322 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002323 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002324 }
2325 }
2326}
2327
2328void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2329{
2330 if (!containsFloats())
2331 return;
2332
2333 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2334 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002335 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002336 m_floatingObjects->remove(curr);
2337 if (floatingObjectSet.isEmpty())
2338 break;
2339 curr = floatingObjectSet.last().get();
2340 }
2341}
2342
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002343LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2344{
2345 LayoutUnit offset = fixedOffset;
2346 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2347 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2348 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2349}
2350
2351LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2352{
2353 LayoutUnit offset = fixedOffset;
2354 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2355 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2356 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2357}
2358
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002359void RenderBlockFlow::computeLogicalLocationForFloat(FloatingObject& floatingObject, LayoutUnit& logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002360{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002361 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002362 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002363 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002364
andersca@apple.com86298632013-11-10 19:32:33 +00002365 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002366
2367 LayoutUnit floatLogicalLeft;
2368
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002369 bool insideFragmentedFlow = enclosingFragmentedFlow();
hyatt@apple.com87515262014-09-04 21:20:12 +00002370 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2371
2372 if (isInitialLetter) {
2373 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2374 if (letterClearance > 0) {
2375 logicalTopOffset += letterClearance;
2376 setLogicalHeight(logicalHeight() + letterClearance);
2377 }
2378 }
2379
akling@apple.com827be9c2013-10-29 02:58:43 +00002380 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002381 LayoutUnit heightRemainingLeft = 1;
2382 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002383 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2384 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < 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 = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
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 }
andersca@apple.com86298632013-11-10 19:32:33 +00002394 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002395 } else {
2396 LayoutUnit heightRemainingLeft = 1;
2397 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002398 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2399 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002400 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002401 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002402 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002403 // Have to re-evaluate all of our offsets, since they may have changed.
2404 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2405 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002406 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002407 }
2408 }
2409 // Use the original width of the float here, since the local variable
2410 // |floatLogicalWidth| was capped to the available line width. See
2411 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002412 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002413 }
2414
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002415 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
2416 LayoutUnit childBeforeMargin = marginBeforeForChild(childBox);
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002417
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002418 if (isInitialLetter)
2419 adjustInitialLetterPosition(childBox, logicalTopOffset, childBeforeMargin);
2420
2421 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
2422 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
2423
2424 setLogicalTopForFloat(floatingObject, logicalTopOffset);
2425 setLogicalTopForChild(childBox, logicalTopOffset + childBeforeMargin);
2426
2427 setLogicalMarginsForFloat(floatingObject, childLogicalLeftMargin, childBeforeMargin);
2428}
2429
2430void RenderBlockFlow::adjustInitialLetterPosition(RenderBox& childBox, LayoutUnit& logicalTopOffset, LayoutUnit& marginBeforeOffset)
2431{
2432 const RenderStyle& style = firstLineStyle();
2433 const FontMetrics& fontMetrics = style.fontMetrics();
2434 if (!fontMetrics.hasCapHeight())
2435 return;
2436
2437 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2438 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2439
2440 // Make an adjustment to align with the cap height of a theoretical block line.
2441 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2442 logicalTopOffset += adjustment;
2443
2444 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2445 // positive for raised and negative for sunken).
2446 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2447
2448 // 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.
2449 if (dropHeightDelta < 0)
2450 marginBeforeOffset += -dropHeightDelta * heightOfLine;
2451
2452 // 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
2453 // empty lines beside the first letter.
2454 if (dropHeightDelta > 0)
2455 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002456}
2457
2458bool RenderBlockFlow::positionNewFloats()
2459{
2460 if (!m_floatingObjects)
2461 return false;
2462
2463 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2464 if (floatingObjectSet.isEmpty())
2465 return false;
2466
2467 // If all floats have already been positioned, then we have no work to do.
2468 if (floatingObjectSet.last()->isPlaced())
2469 return false;
2470
2471 // Move backwards through our floating object list until we find a float that has
2472 // already been positioned. Then we'll be able to move forward, positioning all of
2473 // the new floats that need it.
2474 auto it = floatingObjectSet.end();
2475 --it; // Go to last item.
2476 auto begin = floatingObjectSet.begin();
2477 FloatingObject* lastPlacedFloatingObject = 0;
2478 while (it != begin) {
2479 --it;
2480 if ((*it)->isPlaced()) {
2481 lastPlacedFloatingObject = it->get();
2482 ++it;
2483 break;
2484 }
2485 }
2486
2487 LayoutUnit logicalTop = logicalHeight();
2488
2489 // The float cannot start above the top position of the last positioned float.
2490 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002491 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002492
2493 auto end = floatingObjectSet.end();
2494 // Now walk through the set of unpositioned floats and place them.
2495 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002496 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002497 // The containing block is responsible for positioning floats, so if we have floats in our
2498 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002499 auto& childBox = floatingObject.renderer();
2500 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002501 continue;
2502
weinig@apple.com12840dc2013-10-22 23:59:08 +00002503 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002504
akling@apple.com827be9c2013-10-29 02:58:43 +00002505 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002506 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002507 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002508 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002509
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002510 computeLogicalLocationForFloat(floatingObject, logicalTop);
2511 LayoutUnit childLogicalTop = logicalTopForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002512
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002513 estimateFragmentRangeForBoxChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002514
hyatt@apple.comccad3742015-02-04 21:39:00 +00002515 childBox.markForPaginationRelayoutIfNeeded();
2516 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002517
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002518 LayoutState* layoutState = view().layoutState();
2519 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002520 if (isPaginated) {
2521 // If we are unsplittable and don't fit, then we need to move down.
2522 // We include our margins as part of the unsplittable area.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002523 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, childLogicalTop - logicalTop, marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002524
2525 // See if we have a pagination strut that is making us move down further.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002526 // Note that an unsplittable child can't also have a pagination strut, so this
2527 // is exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002528 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002529 if (childBlock && childBlock->paginationStrut()) {
2530 newLogicalTop += childBlock->paginationStrut();
2531 childBlock->setPaginationStrut(0);
2532 }
2533
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002534 if (newLogicalTop != logicalTop) {
2535 floatingObject.setPaginationStrut(newLogicalTop - logicalTop);
2536 computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002537 if (childBlock)
2538 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002539 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002540 logicalTop = newLogicalTop;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002541 }
2542
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002543 if (updateFragmentRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002544 childBox.setNeedsLayout(MarkOnlyThis);
2545 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002546 }
2547 }
2548
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002549 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + (logicalTopForChild(childBox) - logicalTop) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002550
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002551 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002552
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002553 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002554 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002555 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002556 if (childBox.checkForRepaintDuringLayout())
2557 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002558 }
2559 return true;
2560}
2561
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002562void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002563{
2564 positionNewFloats();
2565 // set y position
2566 LayoutUnit newY = 0;
2567 switch (clear) {
2568 case CLEFT:
2569 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2570 break;
2571 case CRIGHT:
2572 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2573 break;
2574 case CBOTH:
2575 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002576 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002577 default:
2578 break;
2579 }
2580 if (height() < newY)
2581 setLogicalHeight(newY);
2582}
2583
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002584LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002585{
2586 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002587 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002588
2589 return fixedOffset;
2590}
2591
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002592LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002593{
2594 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002595 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002596
2597 return fixedOffset;
2598}
2599
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002600LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002601{
2602 if (!m_floatingObjects)
2603 return logicalHeight;
2604
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002605 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2606}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002607
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002608LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2609{
2610 if (!m_floatingObjects)
2611 return logicalHeight;
2612
2613 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002614}
2615
2616LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) 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.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002626 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002627 }
2628 return lowestFloatBottom;
2629}
2630
hyatt@apple.com87515262014-09-04 21:20:12 +00002631LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2632{
2633 if (!m_floatingObjects)
2634 return 0;
2635 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002636 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2637 auto end = floatingObjectSet.end();
2638 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002639 const auto& floatingObject = *it->get();
2640 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == FIRST_LETTER && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002641 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002642 }
2643 return lowestFloatBottom;
2644}
2645
weinig@apple.com12840dc2013-10-22 23:59:08 +00002646LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002647{
2648 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002649 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002650 return 0;
2651
weinig@apple.com12840dc2013-10-22 23:59:08 +00002652 LayoutUnit childLogicalTop = child.logicalTop();
2653 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002654 LayoutUnit lowestFloatLogicalBottom = 0;
2655
2656 // Floats that will remain the child's responsibility to paint should factor into its
2657 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002658 auto childEnd = child.m_floatingObjects->set().end();
2659 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002660 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002661 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002662 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002663 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002664
2665 if (logicalBottom > logicalHeight()) {
2666 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002667 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002668 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2669 bool shouldPaint = false;
2670
2671 // The nearest enclosing layer always paints the float (so that zindex and stacking
2672 // behaves properly). We always want to propagate the desire to paint the float as
2673 // far out as we can, to the outermost block that overlaps the float, stopping only
2674 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002675 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2676 floatingObject.setShouldPaint(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002677 shouldPaint = true;
2678 }
2679 // We create the floating object list lazily.
2680 if (!m_floatingObjects)
2681 createFloatingObjects();
2682
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002683 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002684 }
2685 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002686 const auto& renderer = floatingObject.renderer();
2687 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2688 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002689 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2690 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2691 // layer.
2692 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2693 // it should paint.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002694 floatingObject.setShouldPaint(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002695 }
2696
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002697 // 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 +00002698 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002699 child.addOverflowFromChild(&renderer, floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002700 }
2701 }
2702 return lowestFloatLogicalBottom;
2703}
2704
weinig@apple.com12840dc2013-10-22 23:59:08 +00002705bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002706{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002707 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002708 return false;
2709
2710 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002711 const auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002712 if (it == floatingObjectSet.end())
2713 return false;
2714
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002715 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002716}
2717
hyatt@apple.com21c60802015-04-01 18:10:32 +00002718void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002719{
2720 ASSERT(!avoidsFloats());
2721
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002722 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2723 if (createsNewFormattingContext())
2724 return;
2725
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002726 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2727 if (!prev->m_floatingObjects)
2728 return;
2729
2730 logicalLeftOffset += marginLogicalLeft();
2731
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002732 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2733 auto prevEnd = prevSet.end();
2734 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002735 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002736 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002737 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002738 // We create the floating object list lazily.
2739 if (!m_floatingObjects)
2740 createFloatingObjects();
2741
2742 // Applying the child's margin makes no sense in the case where the child was passed in.
2743 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2744 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2745 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2746 // will get applied twice.
2747 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002748 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2749 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002750
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002751 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002752 }
2753 }
2754 }
2755}
2756
2757void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2758{
2759 if (!everHadLayout() && !containsFloats())
2760 return;
2761
2762 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2763 setChildNeedsLayout(markParents);
2764
2765 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002766 removeFloatingObject(*floatToRemove);
hyatt@apple.com11a5e5c2016-05-19 21:51:31 +00002767 else if (childrenInline())
hyatt@apple.com00e93142016-05-18 18:59:40 +00002768 return;
2769
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002770 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002771 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2772 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2773 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002774 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002775 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2776 block.setChildNeedsLayout(markParents);
2777 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002778 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002779 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002780 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2781 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002782 }
2783}
2784
2785void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2786{
2787 if (!m_floatingObjects)
2788 return;
2789
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002790 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2791 auto end = floatingObjectSet.end();
2792
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002793 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002794 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002795 continue;
2796
cdumez@apple.come9437792014-10-08 23:33:43 +00002797 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002798 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2799 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002800 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002801 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002802 if (nextBlock.containsFloat(floatingBox))
2803 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002804 }
2805 }
2806}
2807
zalan@apple.com6816b132015-10-17 19:14:53 +00002808LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002809{
akling@apple.com827be9c2013-10-29 02:58:43 +00002810 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002811 return point;
2812
2813 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2814 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2815 // case.
2816 if (isHorizontalWritingMode())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002817 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * child.locationOffsetOfBorderBox().height());
2818 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * child.locationOffsetOfBorderBox().width(), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002819}
2820
weinig@apple.com12840dc2013-10-22 23:59:08 +00002821LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002822{
2823 // There is no need to compute clearance if we have no floats.
2824 if (!containsFloats())
2825 return 0;
2826
2827 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002828 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002829 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002830 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002831 case CNONE:
2832 break;
2833 case CLEFT:
2834 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2835 break;
2836 case CRIGHT:
2837 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2838 break;
2839 case CBOTH:
2840 logicalBottom = lowestFloatLogicalBottom();
2841 break;
2842 }
2843
2844 // 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 +00002845 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002846 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002847 LayoutUnit newLogicalTop = logicalTop;
2848 while (true) {
zalan@apple.com64761fe2016-03-02 21:42:22 +00002849 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002850 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2851 return newLogicalTop - logicalTop;
2852
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002853 RenderFragmentContainer* fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2854 LayoutRect borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002855 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2856
2857 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002858 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2859 LayoutUnit childOldMarginLeft = child.marginLeft();
2860 LayoutUnit childOldMarginRight = child.marginRight();
2861 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002862
weinig@apple.com12840dc2013-10-22 23:59:08 +00002863 child.setLogicalTop(newLogicalTop);
2864 child.updateLogicalWidth();
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002865 fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2866 borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002867 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2868
weinig@apple.com12840dc2013-10-22 23:59:08 +00002869 child.setLogicalTop(childOldLogicalTop);
2870 child.setLogicalWidth(childOldLogicalWidth);
2871 child.setMarginLeft(childOldMarginLeft);
2872 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002873
2874 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2875 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2876 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2877 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2878 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002879 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002880 return newLogicalTop - logicalTop;
2881 }
2882
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002883 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002884 ASSERT(newLogicalTop >= logicalTop);
2885 if (newLogicalTop < logicalTop)
2886 break;
2887 }
2888 ASSERT_NOT_REACHED();
2889 }
2890 return result;
2891}
2892
2893bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2894{
2895 if (!m_floatingObjects)
2896 return false;
2897
2898 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002899 if (is<RenderView>(*this))
2900 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002901
2902 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2903 auto begin = floatingObjectSet.begin();
2904 for (auto it = floatingObjectSet.end(); it != begin;) {
2905 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002906 const auto& floatingObject = *it->get();
2907 auto& renderer = floatingObject.renderer();
2908 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002909 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002910 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002911 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2912 return true;
2913 }
2914 }
2915 }
2916
2917 return false;
2918}
2919
weinig@apple.com611b9292013-10-20 22:57:54 +00002920bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2921{
2922 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002923
darin@apple.come1be6ca2014-04-28 04:19:10 +00002924 if (auto simpleLineLayout = this->simpleLineLayout())
2925 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002926
weinig@apple.com611b9292013-10-20 22:57:54 +00002927 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2928}
2929
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002930void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2931{
akling@apple.com827be9c2013-10-29 02:58:43 +00002932 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002933 return;
2934
2935 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2936 // for either overflow or translations via relative positioning.
2937 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002938 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2939
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002940 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002941 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002942 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002943 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002944 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002945 }
2946 } else {
2947 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2948 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002949 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2950 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002951 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002952 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002953 left = std::min(left, x + obj->x());
2954 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002955 }
2956 }
2957 }
2958 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002959
2960 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002961 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2962 auto end = floatingObjectSet.end();
2963 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002964 const auto& floatingObject = *it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002965 // Only examine the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002966 if (floatingObject.shouldPaint()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002967 LayoutUnit floatLeft = floatingObject.translationOffsetToAncestor().width();
zalan@apple.com6816b132015-10-17 19:14:53 +00002968 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002969 left = std::min(left, floatLeft);
2970 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002971 }
2972 }
2973 }
2974}
2975
2976void RenderBlockFlow::fitBorderToLinesIfNeeded()
2977{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002978 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002979 return;
2980
2981 // Walk any normal flow lines to snugly fit.
2982 LayoutUnit left = LayoutUnit::max();
2983 LayoutUnit right = LayoutUnit::min();
2984 LayoutUnit oldWidth = contentWidth();
2985 adjustForBorderFit(0, left, right);
2986
2987 // Clamp to our existing edges. We can never grow. We only shrink.
2988 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2989 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002990 left = std::min(rightEdge, std::max(leftEdge, left));
2991 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002992
2993 LayoutUnit newContentWidth = right - left;
2994 if (newContentWidth == oldWidth)
2995 return;
2996
2997 setOverrideLogicalContentWidth(newContentWidth);
2998 layoutBlock(false);
2999 clearOverrideLogicalContentWidth();
3000}
3001
3002void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3003{
3004 if (logicalTop >= logicalBottom)
3005 return;
3006
antti@apple.combe9d3e12014-05-11 09:42:47 +00003007 // Floats currently affect the choice whether to use simple line layout path.
3008 if (m_simpleLineLayout) {
3009 invalidateLineLayoutPath();
3010 return;
3011 }
3012
weinig@apple.com611b9292013-10-20 22:57:54 +00003013 RootInlineBox* lowestDirtyLine = lastRootBox();
3014 RootInlineBox* afterLowest = lowestDirtyLine;
3015 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3016 afterLowest = lowestDirtyLine;
3017 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3018 }
3019
3020 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3021 afterLowest->markDirty();
3022 afterLowest = afterLowest->prevRootBox();
3023 }
3024}
3025
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003026std::optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003027{
3028 if (isWritingModeRoot() && !isRubyRun())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003029 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003030
3031 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003032 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003033
antti@apple.com940f5872013-10-24 20:31:11 +00003034 if (!hasLines())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003035 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003036
darin@apple.come1be6ca2014-04-28 04:19:10 +00003037 if (auto simpleLineLayout = this->simpleLineLayout())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003038 return std::optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003039
akling@apple.comee3c8df2013-11-06 08:09:44 +00003040 ASSERT(firstRootBox());
3041 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003042}
3043
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003044std::optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003045{
3046 if (isWritingModeRoot() && !isRubyRun())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003047 return std::optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003048
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003049 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3050 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3051 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003052 if (!childrenInline()) {
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003053 std::optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003054 if (!inlineBlockBaseline)
3055 return inlineBlockBaseline;
3056 lastBaseline = inlineBlockBaseline.value();
3057 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003058 if (!hasLines()) {
3059 if (!hasLineIfEmpty())
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003060 return std::optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003061 const auto& fontMetrics = firstLineStyle().fontMetrics();
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003062 return std::optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003063 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003064 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003065 }
3066
3067 if (auto simpleLineLayout = this->simpleLineLayout())
3068 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3069 else {
3070 bool isFirstLine = lastRootBox() == firstRootBox();
3071 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3072 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3073 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003074 }
3075 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3076 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3077 // enough with the spec to not cause tons of breakages).
utatane.tea@gmail.com43926962016-11-27 06:08:16 +00003078 return std::optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003079}
3080
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003081void RenderBlockFlow::setSelectionState(SelectionState state)
3082{
3083 if (state != SelectionNone)
3084 ensureLineBoxes();
3085 RenderBoxModelObject::setSelectionState(state);
3086}
3087
weinig@apple.com12840dc2013-10-22 23:59:08 +00003088GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003089 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3090{
antti@apple.comfea51992013-10-28 13:39:23 +00003091 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003092
weinig@apple.com611b9292013-10-20 22:57:54 +00003093 GapRects result;
3094
3095 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3096
antti@apple.com0e632aa2013-10-22 21:03:38 +00003097 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003098 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003099 // 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 +00003100 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3101 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3102 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3103 }
3104 return result;
3105 }
3106
3107 RootInlineBox* lastSelectedLine = 0;
3108 RootInlineBox* curr;
3109 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3110
3111 // Now paint the gaps for the lines.
3112 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3113 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3114 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3115
3116 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003117 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003118 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3119
3120 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3121 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003122 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003123 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3124 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3125 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3126
3127 lastSelectedLine = curr;
3128 }
3129
3130 if (containsStart && !lastSelectedLine)
3131 // VisibleSelection must start just after our last line.
3132 lastSelectedLine = lastRootBox();
3133
3134 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003135 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003136 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3137 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3138 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3139 }
3140 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003141}
3142
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003143bool RenderBlockFlow::needsLayoutAfterFragmentRangeChange() const
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003144{
3145 // A block without floats or that expands to enclose them won't need a relayout
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003146 // after a fragment range change. There is no overflow content needing relayout
3147 // in the fragment chain because the fragment range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003148 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003149 return false;
3150
3151 return true;
3152}
3153
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003154void RenderBlockFlow::updateLogicalHeight()
3155{
3156 RenderBlock::updateLogicalHeight();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003157}
3158
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003159void RenderBlockFlow::setMultiColumnFlow(RenderMultiColumnFlow* fragmentedFlow)
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003160{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003161 if (fragmentedFlow || hasRareBlockFlowData()) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003162 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003163 rareData.m_multiColumnFlow = fragmentedFlow;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003164 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003165}
3166
akling@apple.com525dae62014-01-03 20:22:09 +00003167static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003168{
akling@apple.com38f0a652014-02-06 21:24:17 +00003169 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003170}
3171
3172RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3173{
3174 ASSERT(i >= 0);
3175
akling@apple.com827be9c2013-10-29 02:58:43 +00003176 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003177 return nullptr;
3178
3179 if (childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003180 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003181 if (!i--)
3182 return box;
3183 }
akling@apple.com525dae62014-01-03 20:22:09 +00003184 return nullptr;
3185 }
3186
3187 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3188 if (!shouldCheckLines(blockFlow))
3189 continue;
3190 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3191 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003192 }
3193
3194 return nullptr;
3195}
3196
3197int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3198{
akling@apple.com827be9c2013-10-29 02:58:43 +00003199 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003200 return 0;
3201
3202 int count = 0;
3203
3204 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003205 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003206 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003207 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003208 }
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003209 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3210 ++count;
weinig@apple.com17140912013-10-19 19:55:40 +00003211 if (box == stopRootInlineBox) {
3212 if (found)
3213 *found = true;
3214 break;
3215 }
3216 }
akling@apple.com525dae62014-01-03 20:22:09 +00003217 return count;
3218 }
3219
3220 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3221 if (!shouldCheckLines(blockFlow))
3222 continue;
3223 bool recursiveFound = false;
3224 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3225 if (recursiveFound) {
3226 if (found)
3227 *found = true;
3228 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003229 }
3230 }
3231
3232 return count;
3233}
3234
3235static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3236{
akling@apple.com827be9c2013-10-29 02:58:43 +00003237 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003238 return -1;
3239
3240 if (block.childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003241 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003242 if (++count == lineCount)
3243 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3244 }
3245 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003246 RenderBox* normalFlowChildWithoutLines = nullptr;
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003247 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003248 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3249 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003250 if (result != -1)
3251 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003252 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003253 normalFlowChildWithoutLines = obj;
3254 }
3255 if (normalFlowChildWithoutLines && !lineCount)
3256 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3257 }
3258
3259 return -1;
3260}
3261
3262int RenderBlockFlow::heightForLineCount(int lineCount)
3263{
3264 int count = 0;
3265 return getHeightForLineCount(*this, lineCount, true, count);
3266}
3267
3268void RenderBlockFlow::clearTruncation()
3269{
akling@apple.com827be9c2013-10-29 02:58:43 +00003270 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003271 return;
3272
3273 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003274 ensureLineBoxes();
3275
weinig@apple.com17140912013-10-19 19:55:40 +00003276 setHasMarkupTruncation(false);
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003277 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
weinig@apple.com17140912013-10-19 19:55:40 +00003278 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003279 return;
3280 }
3281
3282 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3283 if (shouldCheckLines(blockFlow))
3284 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003285 }
3286}
3287
weinig@apple.com3f23b382013-10-19 20:26:58 +00003288bool RenderBlockFlow::containsNonZeroBidiLevel() const
3289{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003290 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3291 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003292 if (box->bidiLevel())
3293 return true;
3294 }
3295 }
3296 return false;
3297}
3298
weinig@apple.com611b9292013-10-20 22:57:54 +00003299Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3300{
3301 if (!box)
3302 return Position();
3303
3304 if (!box->renderer().nonPseudoNode())
3305 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3306
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003307 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003308 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3309
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003310 auto& textBox = downcast<InlineTextBox>(*box);
3311 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003312}
3313
enrica@apple.com0db51a62016-04-27 23:53:08 +00003314RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
3315{
3316 // A light, non-recursive version of RenderBlock::positionForCoordinates that looks at
3317 // whether a point lies within the gaps between its root line boxes, to be called against
3318 // a node returned from elementAtPoint. We make the assumption that either the node or one
3319 // of its immediate children contains the root line boxes in question.
3320 // See <rdar://problem/6824650> for context.
3321
3322 RenderBlock* block = this;
3323
3324 FloatPoint localPoint = block->absoluteToLocal(point);
3325
3326 if (!block->childrenInline()) {
3327 // Look among our immediate children for an alternate box that contains the point.
3328 for (RenderBox* child = block->firstChildBox(); child; child = child->nextSiblingBox()) {
3329 if (!child->height() || child->style().visibility() != WebCore::VISIBLE || child->isFloatingOrOutOfFlowPositioned())
3330 continue;
3331 float top = child->y();
3332
3333 RenderBox* nextChild = child->nextSiblingBox();
3334 while (nextChild && nextChild->isFloatingOrOutOfFlowPositioned())
3335 nextChild = nextChild->nextSiblingBox();
3336 if (!nextChild) {
3337 if (localPoint.y() >= top) {
3338 block = downcast<RenderBlock>(child);
3339 break;
3340 }
3341 continue;
3342 }
3343
3344 float bottom = nextChild->y();
3345
3346 if (localPoint.y() >= top && localPoint.y() < bottom && is<RenderBlock>(*child)) {
3347 block = downcast<RenderBlock>(child);
3348 break;
3349 }
3350 }
3351
3352 if (!block->childrenInline())
3353 return nullptr;
3354
3355 localPoint = block->absoluteToLocal(point);
3356 }
3357
3358 RenderBlockFlow& blockFlow = downcast<RenderBlockFlow>(*block);
3359
3360 // Only check the gaps between the root line boxes. We deliberately ignore overflow because
3361 // experience has shown that hit tests on an exploded text node can fail when within the
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003362 // overflow fragment.
enrica@apple.com0db51a62016-04-27 23:53:08 +00003363 for (RootInlineBox* current = blockFlow.firstRootBox(); current && current != blockFlow.lastRootBox(); current = current->nextRootBox()) {
3364 float currentBottom = current->y() + current->logicalHeight();
3365 if (localPoint.y() < currentBottom)
3366 return nullptr;
3367
3368 RootInlineBox* next = current->nextRootBox();
3369 float nextTop = next->y();
3370 if (localPoint.y() < nextTop) {
3371 InlineBox* inlineBox = current->closestLeafChildForLogicalLeftPosition(localPoint.x());
3372 if (inlineBox && inlineBox->behavesLikeText() && is<RenderText>(inlineBox->renderer()))
3373 return &downcast<RenderText>(inlineBox->renderer());
3374 }
3375 }
3376 return nullptr;
3377}
3378
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003379VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer* fragment)
weinig@apple.com611b9292013-10-20 22:57:54 +00003380{
3381 ASSERT(childrenInline());
3382
antti@apple.com940f5872013-10-24 20:31:11 +00003383 ensureLineBoxes();
3384
weinig@apple.com611b9292013-10-20 22:57:54 +00003385 if (!firstRootBox())
3386 return createVisiblePosition(0, DOWNSTREAM);
3387
akling@apple.com827be9c2013-10-29 02:58:43 +00003388 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3389 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003390
3391 // look for the closest line box in the root box which is at the passed-in y coordinate
3392 InlineBox* closestBox = 0;
3393 RootInlineBox* firstRootBoxWithChildren = 0;
3394 RootInlineBox* lastRootBoxWithChildren = 0;
3395 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003396 if (fragment && root->containingFragment() != fragment)
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003397 continue;
3398
weinig@apple.com611b9292013-10-20 22:57:54 +00003399 if (!root->firstLeafChild())
3400 continue;
3401 if (!firstRootBoxWithChildren)
3402 firstRootBoxWithChildren = root;
3403
3404 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3405 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3406 break;
3407
3408 lastRootBoxWithChildren = root;
3409
3410 // check if this root line box is located at this y coordinate
3411 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3412 if (linesAreFlipped) {
3413 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3414 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3415 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3416
3417 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3418 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3419 continue;
3420 }
3421 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3422 if (closestBox)
3423 break;
3424 }
3425 }
3426
3427 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3428
3429 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3430 // y coordinate is below last root line box, pretend we hit it
3431 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3432 }
3433
3434 if (closestBox) {
3435 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003436 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003437 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3438 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3439 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3440 if (box->isLineBreak()) {
3441 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3442 box = newBox;
3443 }
3444 // y coordinate is above first root line box, so return the start of the first
3445 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3446 }
3447 }
3448
3449 // pass the box a top position that is inside it
3450 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3451 if (!isHorizontalWritingMode())
3452 point = point.transposedPoint();
3453 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003454 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003455 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003456 }
3457
3458 if (lastRootBoxWithChildren) {
3459 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3460 ASSERT(moveCaretToBoundary);
3461 InlineBox* logicallyLastBox;
3462 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3463 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3464 }
3465
3466 // Can't reach this. We have a root line box, but it has no kids.
3467 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3468 // seems to hit this code path.
3469 return createVisiblePosition(0, DOWNSTREAM);
3470}
3471
zalan@apple.com0d5951b2017-02-19 16:24:20 +00003472Position RenderBlockFlow::positionForPoint(const LayoutPoint& point)
3473{
3474 // FIXME: It supports single text child only (which is the majority of simple line layout supported content at this point).
3475 if (!simpleLineLayout() || firstChild() != lastChild() || !is<RenderText>(firstChild()))
3476 return positionForPoint(point, nullptr).deepEquivalent();
3477 return downcast<RenderText>(*firstChild()).positionForPoint(point);
3478}
3479
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003480VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer*)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003481{
antti@apple.come0e8a562017-09-21 18:29:47 +00003482 return RenderBlock::positionForPoint(point, nullptr);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003483}
3484
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003485void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
weinig@apple.com611b9292013-10-20 22:57:54 +00003486{
antti@apple.com940f5872013-10-24 20:31:11 +00003487 ASSERT(childrenInline());
weinig@apple.com611b9292013-10-20 22:57:54 +00003488 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003489 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3490 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003491 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3492 if (!rect.isEmpty())
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003493 rects.append(rect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003494 }
3495}
3496
3497void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3498{
3499 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003500
darin@apple.come1be6ca2014-04-28 04:19:10 +00003501 if (auto simpleLineLayout = this->simpleLineLayout()) {
3502 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003503 return;
3504 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003505 m_lineBoxes.paint(this, paintInfo, paintOffset);
3506}
3507
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003508bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003509{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003510 if (!multiColumnFlow() || !multiColumnFlow()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003511 return false;
3512
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003513 multiColumnFlow()->setNeedsHeightsRecalculation(false);
3514 multiColumnFlow()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003515
3516 bool needsRelayout;
3517 bool neededRelayout = false;
3518 bool firstPass = true;
3519 do {
3520 // Column heights may change here because of balancing. We may have to do multiple layout
3521 // passes, depending on how the contents is fitted to the changed column heights. In most
3522 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3523 // passes than that, though, but the number of retries should not exceed the number of
3524 // columns, unless we have a bug.
3525 needsRelayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003526 for (RenderMultiColumnSet* multicolSet = multiColumnFlow()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003527 if (multicolSet->recalculateColumnHeight(firstPass))
3528 needsRelayout = true;
3529 if (needsRelayout) {
3530 // Once a column set gets a new column height, that column set and all successive column
3531 // sets need to be laid out over again, since their logical top will be affected by
3532 // this, and therefore their column heights may change as well, at least if the multicol
3533 // height is constrained.
3534 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003535 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003536 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003537 if (needsRelayout) {
3538 // Layout again. Column balancing resulted in a new height.
3539 neededRelayout = true;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003540 multiColumnFlow()->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003541 setChildNeedsLayout(MarkOnlyThis);
3542 if (firstPass)
3543 statePusher.pop();
3544 layoutBlock(false);
3545 }
3546 firstPass = false;
3547 } while (needsRelayout);
3548
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003549 multiColumnFlow()->setInBalancingPass(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003550
3551 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003552}
3553
antti@apple.com940f5872013-10-24 20:31:11 +00003554bool RenderBlockFlow::hasLines() const
3555{
zalan@apple.coma2fe1762016-08-24 18:33:43 +00003556 if (!childrenInline())
3557 return false;
antti@apple.com940f5872013-10-24 20:31:11 +00003558
darin@apple.come1be6ca2014-04-28 04:19:10 +00003559 if (auto simpleLineLayout = this->simpleLineLayout())
3560 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003561
3562 return lineBoxes().firstLineBox();
3563}
3564
antti@apple.com9e891c82014-05-22 06:12:34 +00003565void RenderBlockFlow::invalidateLineLayoutPath()
3566{
akling@apple.coma12fee22015-02-01 02:58:13 +00003567 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003568 case UndeterminedPath:
3569 case ForceLineBoxesPath:
3570 ASSERT(!m_simpleLineLayout);
3571 return;
3572 case LineBoxesPath:
3573 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003574 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003575 return;
3576 case SimpleLinesPath:
3577 // The simple line layout may have become invalid.
3578 m_simpleLineLayout = nullptr;
akling@apple.coma12fee22015-02-01 02:58:13 +00003579 setLineLayoutPath(UndeterminedPath);
zalan@apple.comde191042017-06-06 19:35:56 +00003580 if (needsLayout())
3581 return;
3582 // FIXME: We should just kick off a subtree layout here (if needed at all) see webkit.org/b/172947.
3583 setNeedsLayout();
antti@apple.com9e891c82014-05-22 06:12:34 +00003584 return;
3585 }
3586 ASSERT_NOT_REACHED();
3587}
3588
zalan@apple.come37da962014-12-11 03:29:29 +00003589void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003590{
zalan@apple.come37da962014-12-11 03:29:29 +00003591 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3592 if (needsLayout) {
3593 deleteLineBoxesBeforeSimpleLineLayout();
3594 m_simpleLineLayout = SimpleLineLayout::create(*this);
3595 }
zalan@apple.com5cd09e52017-02-25 02:14:40 +00003596 if (view().layoutState() && view().layoutState()->isPaginated()) {
3597 m_simpleLineLayout->setIsPaginated();
3598 SimpleLineLayout::adjustLinePositionsForPagination(*m_simpleLineLayout, *this);
3599 }
zalan@apple.comd6ab7b52016-11-01 05:35:48 +00003600 for (auto& renderer : childrenOfType<RenderObject>(*this))
3601 renderer.clearNeedsLayout();
antti@apple.com940f5872013-10-24 20:31:11 +00003602 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00003603 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003604 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003605 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003606 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003607 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3608}
3609
3610void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3611{
akling@apple.coma12fee22015-02-01 02:58:13 +00003612 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003613 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003614 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3615 if (is<RenderText>(renderer))
3616 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3617 else if (is<RenderLineBreak>(renderer))
3618 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3619 else
3620 ASSERT_NOT_REACHED();
3621 }
antti@apple.com940f5872013-10-24 20:31:11 +00003622}
3623
3624void RenderBlockFlow::ensureLineBoxes()
3625{
akling@apple.coma12fee22015-02-01 02:58:13 +00003626 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003627 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003628 return;
zalan@apple.comfa5add62017-02-22 19:33:02 +00003629 bool isPaginated = m_simpleLineLayout->isPaginated();
antti@apple.comfea51992013-10-28 13:39:23 +00003630 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003631
3632#if !ASSERT_DISABLED
3633 LayoutUnit oldHeight = logicalHeight();
3634#endif
3635 bool didNeedLayout = needsLayout();
3636
3637 bool relayoutChildren = false;
3638 LayoutUnit repaintLogicalTop;
3639 LayoutUnit repaintLogicalBottom;
zalan@apple.comfa5add62017-02-22 19:33:02 +00003640 if (isPaginated) {
zalan@apple.com6c04c202017-05-01 00:15:38 +00003641 PaginatedLayoutStateMaintainer state(*this);
zalan@apple.comfa5add62017-02-22 19:33:02 +00003642 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
zalan@apple.come9f08212017-04-27 11:02:09 +00003643 // This matches relayoutToAvoidWidows.
3644 if (shouldBreakAtLineToAvoidWidow())
3645 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
zalan@apple.comb16bcdc2017-07-21 21:04:43 +00003646 // FIXME: This is needed as long as simple and normal line layout produce different line breakings.
3647 repaint();
zalan@apple.comfa5add62017-02-22 19:33:02 +00003648 } else
3649 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +00003650
3651 updateLogicalHeight();
3652 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3653
3654 if (!didNeedLayout)
3655 clearNeedsLayout();
3656}
3657
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003658#if ENABLE(TREE_DEBUGGING)
don.olmstead@sony.comd57eb472017-08-10 01:15:14 +00003659void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003660{
weinig@apple.com611b9292013-10-20 22:57:54 +00003661 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.com360de752017-07-06 21:13:24 +00003662 root->outputLineTreeAndMark(stream, markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003663
3664 if (auto simpleLineLayout = this->simpleLineLayout())
zalan@apple.com360de752017-07-06 21:13:24 +00003665 SimpleLineLayout::outputLineLayoutForFlow(stream, *this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003666}
3667#endif
3668
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003669RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3670{
3671 if (hasRareBlockFlowData())
3672 return *m_rareBlockFlowData;
3673 materializeRareBlockFlowData();
3674 return *m_rareBlockFlowData;
3675}
3676
3677void RenderBlockFlow::materializeRareBlockFlowData()
3678{
3679 ASSERT(!hasRareBlockFlowData());
3680 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3681}
3682
dbates@webkit.org102013c2016-09-26 21:51:25 +00003683#if ENABLE(TEXT_AUTOSIZING)
cdumez@apple.com83102df2016-05-19 19:09:41 +00003684static inline bool isVisibleRenderText(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003685{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003686 if (!is<RenderText>(renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003687 return false;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003688
3689 auto& renderText = downcast<RenderText>(renderer);
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003690 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003691}
3692
cdumez@apple.com83102df2016-05-19 19:09:41 +00003693static inline bool resizeTextPermitted(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003694{
3695 // 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 +00003696 for (auto* ancestor = renderer.parent(); ancestor; ancestor = ancestor->parent()) {
aestes@apple.com6751d842014-01-12 02:51:25 +00003697 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.com83102df2016-05-19 19:09:41 +00003698 if (is<HTMLElement>(ancestor->element()) && !ancestor->element()->isInShadowTree()) {
3699 auto& element = downcast<HTMLElement>(*ancestor->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003700 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003701 }
aestes@apple.com6751d842014-01-12 02:51:25 +00003702 }
3703 return true;
3704}
3705
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003706int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003707{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003708 if (style().visibility() != VISIBLE)
3709 return 0;
3710 if (childrenInline())
3711 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003712 // Only descend into list items.
3713 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003714 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3715 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003716 return count;
3717}
3718
cdumez@apple.com83102df2016-05-19 19:09:41 +00003719static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003720{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003721 if (!renderer.isRenderBlock())
aestes@apple.com6751d842014-01-12 02:51:25 +00003722 return true;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003723 if (renderer.isListItem())
3724 return renderer.style().height().type() != Fixed;
aestes@apple.com6751d842014-01-12 02:51:25 +00003725 return false;
3726}
3727
3728// For now, we auto size single lines of text the same as multiple lines.
3729// We've been experimenting with low values for single lines of text.
3730static inline float oneLineTextMultiplier(float specifiedSize)
3731{
3732 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3733}
3734
3735static inline float textMultiplier(float specifiedSize)
3736{
3737 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3738}
3739
3740void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3741{
simon.fraser@apple.com36676e52016-05-07 00:05:58 +00003742 LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
3743
aestes@apple.com6751d842014-01-12 02:51:25 +00003744 // Don't do any work if the block is smaller than the visible area.
3745 if (visibleWidth >= width())
3746 return;
3747
3748 unsigned lineCount;
3749 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003750 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003751 if (!count)
3752 lineCount = NO_LINE;
3753 else if (count == 1)
3754 lineCount = ONE_LINE;
3755 else
3756 lineCount = MULTI_LINE;
3757 } else
3758 lineCount = m_lineCountForTextAutosizing;
3759
3760 ASSERT(lineCount != NOT_SET);
3761 if (lineCount == NO_LINE)
3762 return;
3763
3764 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3765 float scale = visibleWidth / actualWidth;
3766 float minFontSize = roundf(size / scale);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003767
3768 for (auto* descendant = RenderObjectTraversal::firstChild(*this); descendant; ) {
3769 if (!isNonBlocksOrNonFixedHeightListItems(*descendant)) {
3770 descendant = RenderObjectTraversal::nextSkippingChildren(*descendant, this);
3771 continue;
aestes@apple.com6751d842014-01-12 02:51:25 +00003772 }
cdumez@apple.com83102df2016-05-19 19:09:41 +00003773 if (!isVisibleRenderText(*descendant) || !resizeTextPermitted(*descendant)) {
3774 descendant = RenderObjectTraversal::next(*descendant, this);
3775 continue;
3776 }
3777
3778 auto& text = downcast<RenderText>(*descendant);
3779 auto& oldStyle = text.style();
3780 auto& fontDescription = oldStyle.fontDescription();
3781 float specifiedSize = fontDescription.specifiedSize();
3782 float scaledSize = roundf(specifiedSize * scale);
3783 if (scaledSize > 0 && scaledSize < minFontSize) {
3784 // 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.
3785 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3786 if (m_lineCountForTextAutosizing == NOT_SET)
3787 m_lineCountForTextAutosizing = lineCount;
3788 if (m_widthForTextAutosizing == -1)
3789 m_widthForTextAutosizing = actualWidth;
3790
3791 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3792 float candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
3793 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
antti@apple.com4918b4d2017-08-14 13:20:47 +00003794 document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003795 }
3796
3797 descendant = RenderObjectTraversal::nextSkippingChildren(text, this);
aestes@apple.com6751d842014-01-12 02:51:25 +00003798 }
3799}
dbates@webkit.org102013c2016-09-26 21:51:25 +00003800#endif // ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +00003801
hyatt@apple.com80914862017-03-06 18:00:35 +00003802void RenderBlockFlow::layoutExcludedChildren(bool relayoutChildren)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003803{
hyatt@apple.com80914862017-03-06 18:00:35 +00003804 RenderBlock::layoutExcludedChildren(relayoutChildren);
3805
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003806 auto* fragmentedFlow = multiColumnFlow();
3807 if (!fragmentedFlow)
hyatt@apple.com80914862017-03-06 18:00:35 +00003808 return;
3809
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003810 fragmentedFlow->setIsExcludedFromNormalLayout(true);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003811
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003812 setLogicalTopForChild(*fragmentedFlow, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003813
3814 if (relayoutChildren)
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003815 fragmentedFlow->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003816
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003817 if (fragmentedFlow->needsLayout()) {
3818 for (RenderMultiColumnSet* columnSet = fragmentedFlow->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3819 columnSet->prepareForLayout(!fragmentedFlow->inBalancingPass());
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003820
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003821 fragmentedFlow->invalidateFragments(MarkOnlyThis);
3822 fragmentedFlow->setNeedsHeightsRecalculation(true);
3823 fragmentedFlow->layout();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003824 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003825 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3826 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3827 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3828 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3829 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3830 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3831 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3832 // runs get deleted right after every pass.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003833 fragmentedFlow->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003834 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003835 determineLogicalLeftPositionForChild(*fragmentedFlow);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003836}
3837
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003838void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3839{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003840 if (multiColumnFlow() && (!isFieldset() || !newChild->isLegend()))
3841 return multiColumnFlow()->addChild(newChild, beforeChild);
zalan@apple.comba6049c2017-01-28 16:26:48 +00003842 auto* beforeChildOrPlaceholder = beforeChild;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003843 if (auto* containingFragmentedFlow = enclosingFragmentedFlow())
3844 beforeChildOrPlaceholder = containingFragmentedFlow->resolveMovedChild(beforeChild);
zalan@apple.comba6049c2017-01-28 16:26:48 +00003845 RenderBlock::addChild(newChild, beforeChildOrPlaceholder);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003846}
3847
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003848void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003849{
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +00003850 if (!renderTreeBeingDestroyed()) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003851 RenderFragmentedFlow* fragmentedFlow = multiColumnFlow();
3852 if (fragmentedFlow && fragmentedFlow != &oldChild)
3853 fragmentedFlow->fragmentedFlowRelativeWillBeRemoved(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003854 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003855 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003856}
3857
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003858void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003859{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003860 // If we don't use columns or flow threads, then bail.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003861 if (!isRenderFragmentedFlow() && !multiColumnFlow())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003862 return;
3863
3864 // 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 +00003865 if (RenderMultiColumnFlow* fragmentedFlow = multiColumnFlow()) {
zalan@apple.com53e79072016-12-12 20:17:50 +00003866 LayoutUnit newColumnHeight;
3867 if (hasDefiniteLogicalHeight() || view().frameView().pagination().mode != Pagination::Unpaginated) {
zalan@apple.comcca4b692016-12-16 04:37:28 +00003868 auto computedValues = computeLogicalHeight(LayoutUnit(), logicalTop());
zalan@apple.com53e79072016-12-12 20:17:50 +00003869 newColumnHeight = std::max<LayoutUnit>(computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(), 0);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003870 if (fragmentedFlow->columnHeightAvailable() != newColumnHeight)
zalan@apple.com53e79072016-12-12 20:17:50 +00003871 relayoutChildren = true;
3872 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003873 fragmentedFlow->setColumnHeightAvailable(newColumnHeight);
3874 } else if (is<RenderFragmentedFlow>(*this)) {
3875 RenderFragmentedFlow& fragmentedFlow = downcast<RenderFragmentedFlow>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003876
3877 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3878 // is known. The page logical height thing in LayoutState is meaningless for flow
3879 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3880 // thread), but as long as it is used universally as a means to determine whether page
3881 // height is known or not, we need this. Page height is unknown when column balancing is
3882 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3883 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3884 // 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 +00003885 // hack once the old multicol implementation is gone (see also RenderView::pushLayoutStateForPagination).
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003886 pageLogicalHeight = fragmentedFlow.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003887
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003888 pageLogicalHeightChanged = fragmentedFlow.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003889 }
3890}
3891
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003892bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
zalan@apple.com809f4872016-12-08 18:20:01 +00003893{
3894 return willCreateColumns(desiredColumnCount);
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003895}
3896
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003897void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3898{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003899 ASSERT(!!multiColumnFlow() == requiresColumns(count));
3900 if (!multiColumnFlow())
antti@apple.com411949d2017-08-30 17:28:10 +00003901 return;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003902 multiColumnFlow()->setColumnCountAndWidth(count, width);
3903 multiColumnFlow()->setProgressionIsInline(style().hasInlineColumnAxis());
3904 multiColumnFlow()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003905}
3906
cdumez@apple.com78141732014-11-04 23:00:48 +00003907void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003908{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003909 if (!multiColumnFlow())
hyatt@apple.com86919862014-01-27 16:27:45 +00003910 return;
3911
3912 bool needsLayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003913 bool oldProgressionIsInline = multiColumnFlow()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003914 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003915 if (oldProgressionIsInline != newProgressionIsInline) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003916 multiColumnFlow()->setProgressionIsInline(newProgressionIsInline);
hyatt@apple.com86919862014-01-27 16:27:45 +00003917 needsLayout = true;
3918 }
3919
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003920 bool oldProgressionIsReversed = multiColumnFlow()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003921 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003922 if (oldProgressionIsReversed != newProgressionIsReversed) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003923 multiColumnFlow()->setProgressionIsReversed(newProgressionIsReversed);
hyatt@apple.com86919862014-01-27 16:27:45 +00003924 needsLayout = true;
3925 }
3926
3927 if (needsLayout)
3928 setNeedsLayoutAndPrefWidthsRecalc();
3929}
3930
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003931LayoutUnit RenderBlockFlow::computedColumnWidth() const
3932{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003933 if (multiColumnFlow())
3934 return multiColumnFlow()->computedColumnWidth();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003935 return contentLogicalWidth();
3936}
3937
3938unsigned RenderBlockFlow::computedColumnCount() const
3939{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003940 if (multiColumnFlow())
3941 return multiColumnFlow()->computedColumnCount();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003942
3943 return 1;
3944}
3945
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003946bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3947{
3948 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003949 if (!multiColumnFlow() || style().columnProgression() == NormalColumnProgression)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003950 return hasTopOverflow;
3951
3952 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3953 hasTopOverflow = !hasTopOverflow;
3954
3955 return hasTopOverflow;
3956}
3957
3958bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3959{
3960 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003961 if (!multiColumnFlow() || style().columnProgression() == NormalColumnProgression)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003962 return hasLeftOverflow;
3963
3964 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3965 hasLeftOverflow = !hasLeftOverflow;
3966
3967 return hasLeftOverflow;
3968}
3969
zalan@apple.comac6956c2014-09-05 14:18:06 +00003970struct InlineMinMaxIterator {
3971/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3972 inline min/max width calculations. Note the following about the way it walks:
3973 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3974 (2) We do not drill into the children of floats or replaced elements, since you can't break
3975 in the middle of such an element.
3976 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3977 distinct borders/margin/padding that contribute to the min/max width.
3978*/
3979 const RenderBlockFlow& parent;
3980 RenderObject* current;
3981 bool endOfInline;
3982 bool initial;
3983
3984 InlineMinMaxIterator(const RenderBlockFlow& p)
3985 : parent(p)
3986 , current(nullptr)
3987 , endOfInline(false)
3988 , initial(true)
3989 { }
3990
3991 RenderObject* next();
3992};
3993
3994RenderObject* InlineMinMaxIterator::next()
3995{
3996 RenderObject* result = nullptr;
3997 bool oldEndOfInline = endOfInline;
3998 endOfInline = false;
3999 do {
4000 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
4001 result = current->firstChildSlow();
4002 else if (initial) {
4003 result = parent.firstChild();
4004 initial = false;
4005 }
4006
4007 if (!result) {
4008 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4009 if (!oldEndOfInline && current && current->isRenderInline()) {
4010 result = current;
4011 endOfInline = true;
4012 break;
4013 }
4014
4015 while (current && current != &parent) {
4016 result = current->nextSibling();
4017 if (result)
4018 break;
4019 current = current->parent();
4020 if (current && current != &parent && current->isRenderInline()) {
4021 result = current;
4022 endOfInline = true;
4023 break;
4024 }
4025 }
4026 }
4027
4028 if (!result)
4029 break;
4030
4031 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4032 break;
4033
4034 current = result;
4035 result = nullptr;
4036 } while (current || current == &parent);
4037 // Update our position.
4038 current = result;
4039 return result;
4040}
4041
4042static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4043{
4044 if (cssUnit.type() != Auto)
4045 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4046 return 0;
4047}
4048
4049static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4050{
4051 const RenderStyle& childStyle = child.style();
4052 if (endOfInline) {
4053 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4054 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4055 child.borderEnd();
4056 }
4057 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4058 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4059 child.borderStart();
4060}
4061
4062static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4063{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004064 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004065 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004066 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004067 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004068 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
mmaxfield@apple.com21a4dcb2016-03-13 00:36:59 +00004069 float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004070 inlineMax -= spaceWidth + font.wordSpacing();
4071 if (inlineMin > inlineMax)
4072 inlineMin = inlineMax;
4073 }
4074}
4075
4076static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4077{
4078 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4079}
4080
4081void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4082{
4083 float inlineMax = 0;
4084 float inlineMin = 0;
4085
4086 const RenderStyle& styleToUse = style();
4087 RenderBlock* containingBlock = this->containingBlock();
4088 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4089
4090 // If we are at the start of a line, we want to ignore all white-space.
4091 // Also strip spaces if we previously had text that ended in a trailing space.
4092 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004093 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004094
4095 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4096 // very specific cirucumstances (in order to match common WinIE renderings).
4097 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4098 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4099
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004100 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004101
4102 InlineMinMaxIterator childIterator(*this);
4103
4104 // Only gets added to the max preffered width once.
4105 bool addedTextIndent = false;
4106 // Signals the text indent was more negative than the min preferred width
4107 bool hasRemainingNegativeTextIndent = false;
4108
4109 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4110 RenderObject* prevFloat = 0;
4111 bool isPrevChildInlineFlow = false;
4112 bool shouldBreakLineAfterText = false;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004113 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation() & FirstHangingPunctuation;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004114 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation() & LastHangingPunctuation;
4115 RenderText* lastText = nullptr;
4116
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004117 bool addedStartPunctuationHang = false;
4118
zalan@apple.comac6956c2014-09-05 14:18:06 +00004119 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004120 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004121 child->style().autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004122 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004123 // Step One: determine whether or not we need to terminate our current line.
4124 // Each discrete chunk can become the new min-width, if it is the widest chunk
4125 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004126
4127 // Children fall into three categories:
4128 // (1) An inline flow object. These objects always have a min/max of 0,
4129 // and are included in the iteration solely so that their margins can
4130 // be added in.
4131 //
4132 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4133 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004134 // we need to break the current line, and then add in our own margins and min/max
4135 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004136 //
4137 // (3) A text object. Text runs can have breakable characters at the start,
4138 // the middle or the end. They may also lose whitespace off the front if
4139 // we're already ignoring whitespace. In order to compute accurate min-width
4140 // information, we need three pieces of information.
4141 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4142 // starts with whitespace.
4143 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4144 // ends with whitespace.
4145 // (c) the min/max width of the string (trimmed for whitespace).
4146 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004147 // If the text string starts with whitespace, then we need to terminate our current line
4148 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004149 //
4150 // If the text string has a breakable character in the middle, but didn't start
4151 // with whitespace, then we add the width of the first non-breakable run and
4152 // then end the current line. We then need to use the intermediate min/max width
4153 // values (if any of them are larger than our current min/max). We then look at
4154 // the width of the last non-breakable run and use that to start a new line
4155 // (unless we end in whitespace).
4156 const RenderStyle& childStyle = child->style();
4157 float childMin = 0;
4158 float childMax = 0;
4159
4160 if (!child->isText()) {
4161 if (child->isLineBreakOpportunity()) {
4162 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4163 inlineMin = 0;
4164 continue;
4165 }
4166 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004167 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004168 // Add in padding/border/margin from the appropriate side of
4169 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004170 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004171 childMin += bpm;
4172 childMax += bpm;
4173
4174 inlineMin += childMin;
4175 inlineMax += childMax;
4176
4177 child->setPreferredLogicalWidthsDirty(false);
4178 } else {
4179 // Inline replaced elts add in their margins to their min/max values.
hyatt@apple.com14520e42016-04-20 18:01:40 +00004180 if (!child->isFloating())
4181 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004182 LayoutUnit margins = 0;
4183 Length startMargin = childStyle.marginStart();
4184 Length endMargin = childStyle.marginEnd();
4185 if (startMargin.isFixed())
4186 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4187 if (endMargin.isFixed())
4188 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4189 childMin += margins.ceilToFloat();
4190 childMax += margins.ceilToFloat();
4191 }
4192 }
4193
cdumez@apple.comf8022152014-10-15 00:29:51 +00004194 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004195 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004196 // Terminate the current line as far as minwidth is concerned.
hyatt@apple.com247170f2017-02-28 16:23:15 +00004197 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4198 computeChildPreferredLogicalWidths(*child, childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth);
4199 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4200 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004201
4202 bool clearPreviousFloat;
4203 if (child->isFloating()) {
4204 clearPreviousFloat = (prevFloat
4205 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4206 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4207 prevFloat = child;
4208 } else
4209 clearPreviousFloat = false;
4210
4211 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
antti@apple.comae85e112017-08-31 23:27:02 +00004212 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004213 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4214 inlineMin = 0;
4215 }
4216
4217 // If we're supposed to clear the previous float, then terminate maxwidth as well.
antti@apple.comae85e112017-08-31 23:27:02 +00004218 if (clearPreviousFloat) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004219 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4220 inlineMax = 0;
4221 }
4222
4223 // Add in text-indent. This is added in only once.
antti@apple.comae85e112017-08-31 23:27:02 +00004224 if (!addedTextIndent && !child->isFloating()) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004225 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4226 childMin += ceiledIndent;
4227 childMax += ceiledIndent;
4228
4229 if (childMin < 0)
4230 textIndent = LayoutUnit::fromFloatCeil(childMin);
4231 else
4232 addedTextIndent = true;
4233 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004234
antti@apple.comae85e112017-08-31 23:27:02 +00004235 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating())
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004236 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004237
4238 // Add our width to the max.
4239 inlineMax += std::max<float>(0, childMax);
4240
antti@apple.comae85e112017-08-31 23:27:02 +00004241 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText))) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004242 if (child->isFloating())
4243 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4244 else
4245 inlineMin += childMin;
4246 } else {
4247 // Now check our line.
4248 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4249
4250 // Now start a new line.
antti@apple.comae85e112017-08-31 23:27:02 +00004251 inlineMin = 0;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004252 }
4253
4254 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4255 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4256 inlineMin = 0;
4257 }
4258
4259 // We are no longer stripping whitespace at the start of a line.
4260 if (!child->isFloating()) {
4261 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004262 trailingSpaceChild = nullptr;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004263 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004264 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004265 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004266 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004267 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004268
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004269 if (renderText.style().hasTextCombine() && renderText.isCombineText())
zalan@apple.com6cad78f2017-09-19 20:28:29 +00004270 downcast<RenderCombineText>(renderText).combineTextIfNeeded();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004271
4272 // Determine if we have a breakable character. Pass in
4273 // whether or not we should ignore any spaces at the front
4274 // of the string. If those are going to be stripped out,
4275 // then they shouldn't be considered in the breakable char
4276 // check.
4277 bool hasBreakableChar, hasBreak;
4278 float beginMin, endMin;
4279 bool beginWS, endWS;
4280 float beginMax, endMax;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004281 bool strippingBeginWS = stripFrontSpaces;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004282 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004283 hasBreakableChar, hasBreak, beginMax, endMax,
4284 childMin, childMax, stripFrontSpaces);
4285
4286 // This text object will not be rendered, but it may still provide a breaking opportunity.
4287 if (!hasBreak && !childMax) {
4288 if (autoWrap && (beginWS || endWS)) {
4289 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4290 inlineMin = 0;
4291 }
4292 continue;
4293 }
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004294
4295 lastText = &renderText;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004296
4297 if (stripFrontSpaces)
4298 trailingSpaceChild = child;
4299 else
4300 trailingSpaceChild = 0;
4301
4302 // Add in text-indent. This is added in only once.
4303 float ti = 0;
4304 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4305 ti = textIndent.ceilToFloat();
4306 childMin += ti;
4307 beginMin += ti;
4308
4309 // It the text indent negative and larger than the child minimum, we re-use the remainder
4310 // in future minimum calculations, but using the negative value again on the maximum
4311 // will lead to under-counting the max pref width.
4312 if (!addedTextIndent) {
4313 childMax += ti;
4314 beginMax += ti;
4315 addedTextIndent = true;
4316 }
4317
4318 if (childMin < 0) {
4319 textIndent = childMin;
4320 hasRemainingNegativeTextIndent = true;
4321 }
4322 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004323
4324 // See if we have a hanging punctuation situation at the start.
4325 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004326 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4327 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004328 childMin -= hangStartWidth;
4329 beginMin -= hangStartWidth;
4330 childMax -= hangStartWidth;
4331 beginMax -= hangStartWidth;
4332 addedStartPunctuationHang = true;
4333 }
4334
zalan@apple.comac6956c2014-09-05 14:18:06 +00004335 // If we have no breakable characters at all,
4336 // then this is the easy case. We add ourselves to the current
4337 // min and max and continue.
4338 if (!hasBreakableChar)
4339 inlineMin += childMin;
4340 else {
4341 // We have a breakable character. Now we need to know if
4342 // we start and end with whitespace.
4343 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004344 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004345 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4346 } else {
4347 inlineMin += beginMin;
4348 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4349 childMin -= ti;
4350 }
4351
4352 inlineMin = childMin;
4353
4354 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004355 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004356 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4357 inlineMin = 0;
4358 shouldBreakLineAfterText = false;
4359 } else {
4360 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4361 inlineMin = endMin;
4362 shouldBreakLineAfterText = true;
4363 }
4364 }
4365
4366 if (hasBreak) {
4367 inlineMax += beginMax;
4368 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4369 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4370 inlineMax = endMax;
4371 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004372 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004373 } else
4374 inlineMax += std::max<float>(0, childMax);
4375 }
4376
antti@apple.comae85e112017-08-31 23:27:02 +00004377 // Ignore spaces after a list marker.
4378 if (child->isListMarker())
zalan@apple.comac6956c2014-09-05 14:18:06 +00004379 stripFrontSpaces = true;
4380 } else {
4381 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4382 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4383 inlineMin = inlineMax = 0;
4384 stripFrontSpaces = true;
4385 trailingSpaceChild = 0;
4386 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004387 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004388 }
4389
4390 if (!child->isText() && child->isRenderInline())
4391 isPrevChildInlineFlow = true;
4392 else
4393 isPrevChildInlineFlow = false;
4394
4395 oldAutoWrap = autoWrap;
4396 }
4397
4398 if (styleToUse.collapseWhiteSpace())
4399 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004400
4401 if (canHangPunctuationAtEnd && lastText && lastText->textLength() > 0) {
4402 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->textLength() - 1;
4403 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4404 inlineMin -= endHangWidth;
4405 inlineMax -= endHangWidth;
4406 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004407
4408 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4409 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4410}
4411
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004412}
4413// namespace WebCore