blob: fb73b6d9450ca10eadac01dae68144f48feacd96 [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"
jer.noble@apple.com872903d2021-10-08 23:31:51 +000028#include "ElementInlines.h"
bjonesbe@adobe.com67478092013-09-09 22:18:17 +000029#include "FloatingObjects.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000030#include "Frame.h"
zalan@apple.come36543a2014-07-29 01:45:54 +000031#include "FrameSelection.h"
darin@apple.com15708b12014-03-16 16:38:58 +000032#include "HTMLElement.h"
cdumez@apple.coma92c4d62016-05-20 01:50:51 +000033#include "HTMLInputElement.h"
darin@apple.com5917cb12017-11-23 17:32:42 +000034#include "HTMLParserIdioms.h"
cdumez@apple.coma92c4d62016-05-20 01:50:51 +000035#include "HTMLTextAreaElement.h"
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000036#include "HitTestLocation.h"
antti@apple.com633f18b2021-10-02 14:01:35 +000037#include "InlineIteratorBox.h"
psaavedra@igalia.com6c7a18e2022-02-02 20:40:59 +000038#include "InlineIteratorInlineBox.h"
zalan@apple.com1ae704f2022-03-21 00:59:06 +000039#include "InlineIteratorLineBox.h"
antti@apple.com36b223a2021-10-15 20:29:15 +000040#include "InlineIteratorLogicalOrderTraversal.h"
lmoura@igalia.coma81facf2021-10-04 14:50:57 +000041#include "InlineIteratorTextBox.h"
don.olmstead@sony.com208385f2021-10-03 23:00:17 +000042#include "InlineWalker.h"
antti@apple.comd4dda742019-12-03 15:41:43 +000043#include "LayoutIntegrationLineLayout.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000044#include "LayoutRepainter.h"
antti@apple.com6233f162021-06-05 12:19:10 +000045#include "LegacyInlineTextBox.h"
antti@apple.com443deba2021-06-01 13:58:23 +000046#include "LegacyLineLayout.h"
zalan@apple.com928aaf92022-03-18 02:30:52 +000047#include "LineSelection.h"
simon.fraser@apple.com36676e52016-05-07 00:05:58 +000048#include "Logging.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000049#include "RenderCombineText.h"
zalan@apple.coma861dc72021-08-20 12:49:48 +000050#include "RenderDeprecatedFlexibleBox.h"
hyatt@apple.com531e35d2017-04-13 16:37:00 +000051#include "RenderFlexibleBox.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000052#include "RenderInline.h"
akling@apple.comf3028052013-11-04 08:46:06 +000053#include "RenderIterator.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000054#include "RenderLayer.h"
aperez@igalia.comfb063c82021-02-02 08:34:53 +000055#include "RenderLayerScrollableArea.h"
antti@apple.comf41183e2018-12-07 20:10:14 +000056#include "RenderLayoutState.h"
zalan@apple.com8bf2a912015-04-10 03:15:50 +000057#include "RenderLineBreak.h"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000058#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000059#include "RenderMarquee.h"
hyatt@apple.com4e0bf862017-09-27 20:54:17 +000060#include "RenderMultiColumnFlow.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000061#include "RenderMultiColumnSet.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000062#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000063#include "RenderText.h"
antti@apple.com89b8fff2017-12-16 19:07:55 +000064#include "RenderTreeBuilder.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000065#include "RenderView.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000066#include "Settings.h"
antti@apple.com4918b4d2017-08-14 13:20:47 +000067#include "TextAutoSizing.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000068#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000069#include "VisiblePosition.h"
fpizlo@apple.comd03c5942017-11-07 19:21:52 +000070#include <wtf/IsoMallocInlines.h>
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000071
hyatt@apple.com5388e672013-09-06 20:54:47 +000072namespace WebCore {
73
antti@apple.com8782b5c2021-11-22 23:32:20 +000074#define ENABLE_MODERN_PREFERRED_WIDTH_COMPUTATION 1
zalan@apple.com51fcd922022-01-19 00:13:13 +000075#define ENABLE_MODERN_PREFERRED_WIDTH_COMPUTATION_FOR_INLINE_BOXES 1
antti@apple.com5072de92021-11-02 16:01:26 +000076
fpizlo@apple.comd03c5942017-11-07 19:21:52 +000077WTF_MAKE_ISO_ALLOCATED_IMPL(RenderBlockFlow);
78
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000079bool RenderBlock::s_canPropagateFloatIntoSibling = false;
80
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000081struct SameSizeAsMarginInfo {
82 uint32_t bitfields : 16;
83 LayoutUnit margins[2];
84};
85
ysuzuki@apple.com82d570e2022-03-26 22:19:31 +000086static_assert(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), "MarginValues should stay small");
87static_assert(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), "MarginInfo should stay small");
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000088
89// 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)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000096{
akling@apple.com827be9c2013-10-29 02:58:43 +000097 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000098 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000099 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000100
ntim@apple.comacb16d42021-12-24 18:55:35 +0000101 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000102
103 // If any height other than auto is specified in CSS, then we don't collapse our bottom
104 // margins with our children's margins. To do otherwise would be to risk odd visual
105 // effects when the children overflow out of the parent block and yet still collapse
106 // with it. We also don't collapse if we have any bottom border/padding.
107 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
ntim@apple.comacb16d42021-12-24 18:55:35 +0000108 && blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000109
weinig@apple.com12840dc2013-10-22 23:59:08 +0000110 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000111
ntim@apple.comacb16d42021-12-24 18:55:35 +0000112 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block.maxPositiveMarginBefore() : 0_lu;
113 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block.maxNegativeMarginBefore() : 0_lu;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000114}
115
antti@apple.com454418f2016-04-25 19:49:23 +0000116RenderBlockFlow::RenderBlockFlow(Element& element, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000117 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
dbates@webkit.org102013c2016-09-26 21:51:25 +0000118#if ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +0000119 , m_widthForTextAutosizing(-1)
120 , m_lineCountForTextAutosizing(NOT_SET)
121#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000122{
weinig@apple.com611b9292013-10-20 22:57:54 +0000123 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000124}
125
antti@apple.com454418f2016-04-25 19:49:23 +0000126RenderBlockFlow::RenderBlockFlow(Document& document, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000127 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
dbates@webkit.org102013c2016-09-26 21:51:25 +0000128#if ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +0000129 , m_widthForTextAutosizing(-1)
130 , m_lineCountForTextAutosizing(NOT_SET)
131#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000132{
weinig@apple.com611b9292013-10-20 22:57:54 +0000133 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000134}
135
136RenderBlockFlow::~RenderBlockFlow()
137{
simon.fraser@apple.com9812a452017-03-20 17:28:55 +0000138 // Do not add any code here. Add it to willBeDestroyed() instead.
hyatt@apple.com5388e672013-09-06 20:54:47 +0000139}
140
zalan@apple.comfde57e42018-02-22 00:20:40 +0000141void RenderBlockFlow::willBeDestroyed()
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000142{
simon.fraser@apple.comb59c6902017-03-17 00:20:45 +0000143 if (!renderTreeBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000144 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000145 // We can't wait for RenderBox::destroy to clear the selection,
146 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000147 if (isSelectionBorder())
jacob_uphoff@apple.com5a6faad2020-03-30 21:13:50 +0000148 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000149
150 // If we are an anonymous block, then our line boxes might have children
151 // that will outlast this block. In the non-anonymous block case those
152 // children will be destroyed by the time we return from this function.
153 if (isAnonymousBlock()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +0000154 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000155 while (auto childBox = box->firstChild())
156 childBox->removeFromParent();
157 }
158 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000159 } else if (parent())
160 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000161 }
162
antti@apple.com443deba2021-06-01 13:58:23 +0000163 if (legacyLineLayout())
164 legacyLineLayout()->lineBoxes().deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000165
simon.fraser@apple.com9812a452017-03-20 17:28:55 +0000166 blockWillBeDestroyed();
weinig@apple.com611b9292013-10-20 22:57:54 +0000167
168 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
zalan@apple.comfde57e42018-02-22 00:20:40 +0000169 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000170}
171
ggaren@apple.com91592ea2019-05-29 21:15:54 +0000172RenderMultiColumnFlow* RenderBlockFlow::multiColumnFlowSlowCase() const
173{
174 return rareBlockFlowData()->m_multiColumnFlow.get();
175}
176
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000177RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
178{
179 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
180 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
181 // to avoid floats.
182 parentHasFloats = false;
183 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
184 if (is<RenderBlockFlow>(*sibling)) {
185 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
186 if (!siblingBlock.avoidsFloats())
187 return &siblingBlock;
188 }
189 if (sibling->isFloating())
190 parentHasFloats = true;
191 }
192 return nullptr;
193}
194
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000195void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000196{
197 if (m_floatingObjects)
198 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
199
200 HashSet<RenderBox*> oldIntrudingFloatSet;
201 if (!childrenInline() && m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000202 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
203 auto end = floatingObjectSet.end();
204 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
205 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000206 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000207 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000208 }
209 }
210
darin@apple.com8152c8ba2022-01-15 22:29:21 +0000211 // Inline blocks are covered by the isReplacedOrInlineBlock() check in the avoidFloats method.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000212 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000213 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000214 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000215 if (!oldIntrudingFloatSet.isEmpty())
216 markAllDescendantsWithFloatsForLayout();
217 return;
218 }
219
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000220 RendererToFloatInfoMap floatMap;
221
222 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000223 if (childrenInline())
224 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
225 else
226 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000227 }
228
229 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
230 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
231 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
antti@apple.comae85e112017-08-31 23:27:02 +0000232 if (!is<RenderBlockFlow>(parent()))
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000233 return;
234
robert@webkit.org97037ef2013-11-20 19:26:10 +0000235 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
236 // them (as opposed to floats they contain themselves) so check for those here too.
antti@apple.comae85e112017-08-31 23:27:02 +0000237 auto& parentBlock = downcast<RenderBlockFlow>(*parent());
238 bool parentHasFloats = false;
239 RenderBlockFlow* previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000240 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000241 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000242 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000243
ross.kirsling@sony.combd744282018-11-18 03:14:31 +0000244 LayoutUnit logicalLeftOffset;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000245 if (previousBlock)
246 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000247 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000248 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000249 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000250 }
251
252 // 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 +0000253 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000254 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000255
256 if (childrenInline()) {
257 LayoutUnit changeLogicalTop = LayoutUnit::max();
258 LayoutUnit changeLogicalBottom = LayoutUnit::min();
259 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000260 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
261 auto end = floatingObjectSet.end();
262 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000263 const auto& floatingObject = *it->get();
264 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000265 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000266 if (oldFloatingObject) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000267 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
268 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000269 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000270 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000271 } else {
272 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000273 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
274 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000275 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000276 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000277 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000278 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000279 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
280 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000281 }
282 }
283
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000284 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
285 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
286 oldFloatingObject->originatingLine()->markDirty();
287 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000288 } else {
289 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000290 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000291 }
292 }
293 }
294
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000295 auto end = floatMap.end();
296 for (auto it = floatMap.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000297 const auto& floatingObject = *it->value.get();
298 if (!floatingObject.isDescendant()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000299 changeLogicalTop = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000300 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000301 }
302 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000303
304 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
305 } else if (!oldIntrudingFloatSet.isEmpty()) {
306 // If there are previously intruding floats that no longer intrude, then children with floats
307 // should also get layout because they might need their floating object lists cleared.
308 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
309 markAllDescendantsWithFloatsForLayout();
310 else {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000311 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
312 auto end = floatingObjectSet.end();
313 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
314 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000315 if (!oldIntrudingFloatSet.isEmpty())
316 markAllDescendantsWithFloatsForLayout();
317 }
318 }
319}
320
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000321void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
322{
323 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
324 // The min/max intrinsic widths calculated really tell how much space elements need when
325 // laid out inside the columns. In order to eventually end up with the desired column width,
326 // we need to convert them to values pertaining to the multicol container.
327 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
328 LayoutUnit columnWidth;
329 LayoutUnit colGap = columnGap();
330 LayoutUnit gapExtra = (columnCount - 1) * colGap;
331 if (style().hasAutoColumnWidth())
332 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
333 else {
334 columnWidth = style().columnWidth();
335 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
336 }
337 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
338 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
339 // performing a layout pass, but this is not an appropriate time or place for layout. The
340 // good news is that if height is unconstrained and there are no explicit breaks, the
341 // resolved column-count really should be 1.
342 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
343 }
344}
345
346void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
347{
simon.fraser@apple.com45a5d9a2022-05-07 02:07:00 +0000348 auto shouldIgnoreDescendantContentForLogicalWidth = shouldApplySizeOrStyleContainment({ Containment::Size, Containment::InlineSize });
zalan@apple.com0b73b012022-04-05 15:44:42 +0000349 if (!shouldIgnoreDescendantContentForLogicalWidth) {
cathiechen@igalia.come80ce682021-05-11 12:49:46 +0000350 if (childrenInline())
351 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
352 else
353 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
354 }
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000355
356 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
357
358 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
359
360 if (!style().autoWrap() && childrenInline()) {
361 // A horizontal marquee with inline children has no minimum width.
zimmermann@webkit.orge0565242021-01-25 21:37:54 +0000362 auto* scrollableArea = layer() ? layer()->scrollableArea() : nullptr;
363 if (scrollableArea && scrollableArea->marquee() && scrollableArea->marquee()->isHorizontal())
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000364 minLogicalWidth = 0;
365 }
366
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000367 if (is<RenderTableCell>(*this)) {
368 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000369 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
zalan@apple.coma4d4f362020-12-19 22:10:14 +0000370 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth));
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000371 }
372
rego@igalia.com76760c72015-05-14 16:37:27 +0000373 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000374 maxLogicalWidth += scrollbarWidth;
375 minLogicalWidth += scrollbarWidth;
376}
377
378bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
379{
380 bool changed = recomputeLogicalWidth();
381
382 LayoutUnit oldColumnWidth = computedColumnWidth();
383 computeColumnCountAndWidth();
384
385 return changed || oldColumnWidth != computedColumnWidth();
386}
387
388LayoutUnit RenderBlockFlow::columnGap() const
389{
rego@igalia.comfcd8dd02018-01-26 14:57:47 +0000390 if (style().columnGap().isNormal())
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000391 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
rego@igalia.comfcd8dd02018-01-26 14:57:47 +0000392 return valueForLength(style().columnGap().length(), availableLogicalWidth());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000393}
394
395void RenderBlockFlow::computeColumnCountAndWidth()
zalan@apple.com748d3822016-12-02 21:25:15 +0000396{
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000397 // Calculate our column width and column count.
398 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
399 unsigned desiredColumnCount = 1;
400 LayoutUnit desiredColumnWidth = contentLogicalWidth();
zalan@apple.com08aaba72016-12-02 23:05:48 +0000401
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000402 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
403 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
404 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
405 return;
406 }
zalan@apple.com08aaba72016-12-02 23:05:48 +0000407
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000408 LayoutUnit availWidth = desiredColumnWidth;
409 LayoutUnit colGap = columnGap();
ross.kirsling@sony.com80414652019-05-21 01:36:11 +0000410 LayoutUnit colWidth = std::max(1_lu, LayoutUnit(style().columnWidth()));
zalan@apple.com585798f2016-05-18 23:25:47 +0000411 unsigned colCount = std::max<unsigned>(1, style().columnCount());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000412
413 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
414 desiredColumnCount = colCount;
415 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
416 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
zalan@apple.com08aaba72016-12-02 23:05:48 +0000417 desiredColumnCount = std::max<unsigned>(1, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned());
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000418 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
419 } else {
zalan@apple.com08aaba72016-12-02 23:05:48 +0000420 desiredColumnCount = std::max<unsigned>(std::min(colCount, ((availWidth + colGap) / (colWidth + colGap)).toUnsigned()), 1);
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000421 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
422 }
423 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
424}
425
darin@apple.coma4ddc782021-05-30 16:11:40 +0000426bool RenderBlockFlow::willCreateColumns(std::optional<unsigned> desiredColumnCount) const
zalan@apple.com748d3822016-12-02 21:25:15 +0000427{
zalan@apple.com809f4872016-12-08 18:20:01 +0000428 // The following types are not supposed to create multicol context.
hyatt@apple.com80914862017-03-06 18:00:35 +0000429 if (isFileUploadControl() || isTextControl() || isListBox())
zalan@apple.com809f4872016-12-08 18:20:01 +0000430 return false;
commit-queue@webkit.org875cdb32017-10-02 17:59:36 +0000431 if (isRenderSVGBlock() || isRubyRun())
antti@apple.com411949d2017-08-30 17:28:10 +0000432 return false;
commit-queue@webkit.org875cdb32017-10-02 17:59:36 +0000433#if ENABLE(MATHML)
434 if (isRenderMathMLBlock())
435 return false;
436#endif // ENABLE(MATHML)
zalan@apple.com809f4872016-12-08 18:20:01 +0000437
zalan@apple.com748d3822016-12-02 21:25:15 +0000438 if (!firstChild())
439 return false;
440
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +0000441 if (style().styleType() != PseudoId::None)
antti@apple.com411949d2017-08-30 17:28:10 +0000442 return false;
443
zalan@apple.com809f4872016-12-08 18:20:01 +0000444 // 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.
commit-queue@webkit.org1a4e6672018-05-21 16:55:45 +0000445 if ((style().overflowY() == Overflow::PagedX || style().overflowY() == Overflow::PagedY) && !(isDocumentElementRenderer() || isBody()))
zalan@apple.com809f4872016-12-08 18:20:01 +0000446 return true;
zalan@apple.com2b9b6102018-07-25 22:44:48 +0000447
zalan@apple.com748d3822016-12-02 21:25:15 +0000448 if (!style().specifiesColumns())
449 return false;
450
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000451 // column-axis with opposite writing direction initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000452 if (!style().hasInlineColumnAxis())
453 return true;
454
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000455 // Non-auto column-width always initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000456 if (!style().hasAutoColumnWidth())
457 return true;
458
zalan@apple.com809f4872016-12-08 18:20:01 +0000459 if (desiredColumnCount)
460 return desiredColumnCount.value() > 1;
461
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000462 // column-count > 1 always initiates MultiColumnFlow.
zalan@apple.com748d3822016-12-02 21:25:15 +0000463 if (!style().hasAutoColumnCount())
464 return style().columnCount() > 1;
465
466 ASSERT_NOT_REACHED();
467 return false;
468}
469
antti@apple.com0f90b2a2020-12-22 18:11:42 +0000470void RenderBlockFlow::setChildrenInline(bool value)
471{
472 if (childrenInline() && !value) {
473 setLineLayoutPath(UndeterminedPath);
commit-queue@webkit.org1acd7232021-10-12 20:43:49 +0000474 m_lineLayout = std::monostate();
antti@apple.com0f90b2a2020-12-22 18:11:42 +0000475 }
476
477 RenderBlock::setChildrenInline(value);
478}
479
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000480void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
481{
482 ASSERT(needsLayout());
483
484 if (!relayoutChildren && simplifiedLayout())
485 return;
486
487 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
488
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000489 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000490 relayoutChildren = true;
491
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000492 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000493
494 LayoutUnit previousHeight = logicalHeight();
495 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
496 // for consistency with other render classes?
zalan@apple.comad3d6b72019-11-20 23:52:40 +0000497 resetLogicalHeightBeforeLayoutIfNeeded();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000498
499 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000500 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000501
ross.kirsling@sony.combd744282018-11-18 03:14:31 +0000502 LayoutUnit repaintLogicalTop;
503 LayoutUnit repaintLogicalBottom;
504 LayoutUnit maxFloatLogicalBottom;
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000505 const RenderStyle& styleToUse = style();
commit-queue@webkit.org795b46f2022-02-28 22:09:24 +0000506 do {
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000507 LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000508
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000509 preparePaginationBeforeBlockLayout(relayoutChildren);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000510
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000511 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
512 // our current maximal positive and negative margins. These values are used when we
513 // are collapsed with adjacent blocks, so for example, if you have block A and B
514 // collapsing together, then you'd take the maximal positive margin from both A and B
515 // and subtract it from the maximal negative margin from both A and B to get the
516 // true collapsed margin. This algorithm is recursive, so when we finish layout()
517 // our block knows its current maximal positive/negative values.
518 //
519 // Start out by setting our margin values to our current margins. Table cells have
520 // no margins, so we don't fill in the values for table cells.
521 bool isCell = isTableCell();
522 if (!isCell) {
523 initMaxMarginValues();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000524
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000525 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
526 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
527 setPaginationStrut(0);
528 }
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000529 if (!firstChild() && !isAnonymousBlock())
530 setChildrenInline(true);
commit-queue@webkit.org344bd0c2021-10-15 06:24:33 +0000531 dirtyForLayoutFromPercentageHeightDescendants();
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000532 if (childrenInline())
533 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
534 else
535 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
commit-queue@webkit.org795b46f2022-02-28 22:09:24 +0000536 // Expand our intrinsic height to encompass floats.
537 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
538 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
539 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
540 if (shouldBreakAtLineToAvoidWidow()) {
541 setEverHadLayout(true);
542 continue;
543 }
544 break;
545 } while (true);
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000546
commit-queue@webkit.org795b46f2022-02-28 22:09:24 +0000547 if (relayoutForPagination()) {
zalan@apple.com4a440322017-11-10 00:31:24 +0000548 ASSERT(!shouldBreakAtLineToAvoidWidow());
549 return;
550 }
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000551
zalan@apple.com4a440322017-11-10 00:31:24 +0000552 // Calculate our new height.
553 LayoutUnit oldHeight = logicalHeight();
554 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000555
zalan@apple.com4a440322017-11-10 00:31:24 +0000556 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
557 // This ensures the size information is correctly computed for the last auto-height fragment receiving content.
558 if (is<RenderFragmentedFlow>(*this))
559 downcast<RenderFragmentedFlow>(*this).applyBreakAfterContent(oldClientAfterEdge);
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000560
zalan@apple.com4a440322017-11-10 00:31:24 +0000561 updateLogicalHeight();
562 LayoutUnit newHeight = logicalHeight();
563 {
commit-queue@webkit.org795b46f2022-02-28 22:09:24 +0000564 // FIXME: This could be removed once relayoutForPagination() either stop recursing or we manage to
zalan@apple.com4a440322017-11-10 00:31:24 +0000565 // re-order them.
566 LayoutStateMaintainer statePusher(*this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000567
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000568 if (oldHeight != newHeight) {
569 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
570 // One of our children's floats may have become an overhanging float for us. We need to look for it.
571 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
572 if (blockFlow.isFloatingOrOutOfFlowPositioned())
573 continue;
574 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
575 addOverhangingFloats(blockFlow, false);
576 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000577 }
578 }
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000579
580 bool heightChanged = (previousHeight != newHeight);
581 if (heightChanged)
582 relayoutChildren = true;
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000583 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000584 }
zalan@apple.com4a440322017-11-10 00:31:24 +0000585 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
586 computeOverflow(oldClientAfterEdge);
587
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000588 auto* state = view().frameView().layoutContext().layoutState();
zalan@apple.com7fd79ce2017-11-08 15:02:10 +0000589 if (state && state->pageLogicalHeight())
zalan@apple.com85ab1ec2017-11-07 21:36:07 +0000590 setPageLogicalOffset(state->pageLogicalOffset(this, logicalTop()));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000591
592 updateLayerTransform();
593
594 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
595 // we overflow or not.
596 updateScrollInfoAfterLayout();
597
598 // FIXME: This repaint logic should be moved into a separate helper function!
599 // Repaint with our new bounds if they are different from our old bounds.
600 bool didFullRepaint = repainter.repaintAfterLayout();
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +0000601 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == Visibility::Visible || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000602 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
commit-queue@webkit.org922b5ea2021-07-14 20:40:50 +0000603 // it had to lay out. We wouldn't need the hasNonVisibleOverflow() hack in that case either.
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000604 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
605 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
commit-queue@webkit.org922b5ea2021-07-14 20:40:50 +0000606 if (hasNonVisibleOverflow()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000607 // 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.
commit-queue@webkit.org922b5ea2021-07-14 20:40:50 +0000608 // Note the old code did this as well but even for overflow:visible. The addition of hasNonVisibleOverflow() at least tightens up the hack a bit.
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000609 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000610 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
611 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000612 }
613
614 LayoutRect repaintRect;
615 if (isHorizontalWritingMode())
616 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
617 else
618 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
619
commit-queue@webkit.org922b5ea2021-07-14 20:40:50 +0000620 if (hasNonVisibleOverflow()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000621 // Adjust repaint rect for scroll offset
simon.fraser@apple.com24e03ba2016-05-11 04:48:08 +0000622 repaintRect.moveBy(-scrollPosition());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000623
624 // Don't allow this rect to spill out of our overflow box.
625 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
626 }
627
628 // Make sure the rect is still non-empty after intersecting for overflow above
629 if (!repaintRect.isEmpty()) {
630 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
631 if (hasReflection())
632 repaintRectangle(reflectedRect(repaintRect));
633 }
634 }
635
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000636 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000637}
638
639void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
640{
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000641 LayoutUnit beforeEdge = borderAndPaddingBefore();
642 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
643
644 setLogicalHeight(beforeEdge);
645
646 // Lay out our hypothetical grid line as though it occurs at the top of the block.
zalan@apple.com4de96c52017-11-07 04:09:59 +0000647 if (view().frameView().layoutContext().layoutState()->lineGrid() == this)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000648 layoutLineGridBox();
649
650 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000651 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000652
653 // Fieldsets need to find their legend and position it inside the border of the object.
654 // The legend then gets skipped during normal layout. The same is true for ruby text.
655 // It doesn't get included in the normal layout process but is instead skipped.
hyatt@apple.com80914862017-03-06 18:00:35 +0000656 layoutExcludedChildren(relayoutChildren);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000657
ross.kirsling@sony.combd744282018-11-18 03:14:31 +0000658 LayoutUnit previousFloatLogicalBottom;
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000659 maxFloatLogicalBottom = 0;
660
661 RenderBox* next = firstChildBox();
662
663 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000664 RenderBox& child = *next;
665 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000666
hyatt@apple.com80914862017-03-06 18:00:35 +0000667 if (child.isExcludedFromNormalLayout())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000668 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
669
670 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
671
weinig@apple.com12840dc2013-10-22 23:59:08 +0000672 if (child.isOutOfFlowPositioned()) {
673 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000674 adjustPositionedBlock(child, marginInfo);
675 continue;
676 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000677 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000678 insertFloatingObject(child);
679 adjustFloatingBlock(marginInfo);
680 continue;
681 }
682
683 // Lay out the child.
684 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
685 }
686
687 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
688 // determining the correct collapsed bottom margin information.
689 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
690}
691
antti@apple.com5072de92021-11-02 16:01:26 +0000692void RenderBlockFlow::computeAndSetLineLayoutPath()
antti@apple.com940f5872013-10-24 20:31:11 +0000693{
antti@apple.com5072de92021-11-02 16:01:26 +0000694 if (lineLayoutPath() != UndeterminedPath)
695 return;
696
697 auto compute = [&] {
antti@apple.com1880e712019-11-26 20:15:39 +0000698#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.comf7ac1cc2020-09-23 12:03:57 +0000699 if (LayoutIntegration::LineLayout::canUseFor(*this))
antti@apple.com561f2f72020-10-26 20:23:48 +0000700 return ModernPath;
antti@apple.com1880e712019-11-26 20:15:39 +0000701#endif
zalan@apple.com515e3702021-10-11 15:55:01 +0000702 return LegacyPath;
antti@apple.com1880e712019-11-26 20:15:39 +0000703 };
704
antti@apple.com5072de92021-11-02 16:01:26 +0000705 setLineLayoutPath(compute());
706}
707
708void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
709{
710 computeAndSetLineLayoutPath();
antti@apple.com42fb53d2013-10-25 02:33:11 +0000711
antti@apple.com1880e712019-11-26 20:15:39 +0000712#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +0000713 if (lineLayoutPath() == ModernPath) {
714 layoutModernLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com1880e712019-11-26 20:15:39 +0000715 return;
716 }
717#endif
718
antti@apple.com443deba2021-06-01 13:58:23 +0000719 if (!legacyLineLayout())
720 m_lineLayout = makeUnique<LegacyLineLayout>(*this);
antti@apple.comc6a9c732019-08-12 15:31:34 +0000721
antti@apple.com443deba2021-06-01 13:58:23 +0000722 legacyLineLayout()->layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000723}
724
weinig@apple.com12840dc2013-10-22 23:59:08 +0000725void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000726{
727 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
728 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
729
730 // The child is a normal flow object. Compute the margins we will use for collapsing now.
mmaxfield@apple.com09804f42016-03-23 00:58:34 +0000731 child.computeAndSetBlockDirectionMargins(*this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000732
733 // Try to guess our correct logical top position. In most cases this guess will
734 // be correct. Only if we're wrong (when we compute the real logical top position)
735 // will we have to potentially relayout.
736 LayoutUnit estimateWithoutPagination;
737 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
738
739 // 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 +0000740 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000741 LayoutUnit oldLogicalTop = logicalTopForChild(child);
742
mark.lam@apple.com65724362020-01-06 22:24:50 +0000743#if ASSERT_ENABLED
zalan@apple.com4de96c52017-11-07 04:09:59 +0000744 LayoutSize oldLayoutDelta = view().frameView().layoutContext().layoutDelta();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000745#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000746 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000747 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000748 estimateFragmentRangeForBoxChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000749
cdumez@apple.com5f02e632022-01-16 01:33:25 +0000750 auto* childBlockFlow = dynamicDowncast<RenderBlockFlow>(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000751 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000752 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000753 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000754 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
755 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
756 // very large elements. If it does the comparison with oldLogicalTop might yield a
757 // false negative as adding and removing margins, borders etc from a saturated number
758 // might yield incorrect results. If this is the case always mark for layout.
759 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000760 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000761 // If an element might be affected by the presence of floats, then always mark it for
762 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000763 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000764 if (fb > logicalTopEstimate)
765 markDescendantsWithFloats = true;
766 }
767
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000768 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000769 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000770 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000771 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000772 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000773 }
774
hyatt@apple.comccad3742015-02-04 21:39:00 +0000775 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000776
weinig@apple.com12840dc2013-10-22 23:59:08 +0000777 bool childHadLayout = child.everHadLayout();
778 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000779 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000780 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000781
782 // Cache if we are at the top of the block right now.
783 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
784
785 // Now determine the correct ypos based off examination of collapsing margin
786 // values.
787 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
788
789 // Now check for clear.
790 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
791
zalan@apple.com4de96c52017-11-07 04:09:59 +0000792 bool paginated = view().frameView().layoutContext().layoutState()->isPaginated();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000793 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000794 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000795
796 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
797
798 // Now we have a final top position. See if it really does end up being different from our estimate.
799 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
800 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000801 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
802 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000803 // The child's width depends on the line width. When the child shifts to clear an item, its width can
804 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000805 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000806 }
807
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000808 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000809 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000810 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000811 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000812 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000813 }
814
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000815 if (updateFragmentRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000816 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000817
818 // In case our guess was wrong, relayout the child.
819 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000820
821 // We are no longer at the top of the block if we encounter a non-empty child.
822 // 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 +0000823 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000824 marginInfo.setAtBeforeSideOfBlock(false);
825
826 // Now place the child in the correct left position
827 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
828
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000829 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000830 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
ntim@apple.comacb16d42021-12-24 18:55:35 +0000831
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000832 // If the child has overhanging floats that intrude into following siblings (or possibly out
833 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000834 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000835 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000836
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000837 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000838 if (childOffset.width() || childOffset.height()) {
zalan@apple.com4de96c52017-11-07 04:09:59 +0000839 view().frameView().layoutContext().addLayoutDelta(childOffset);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000840
841 // If the child moved, we have to repaint it as well as any floating/positioned
842 // descendants. An exception is if we need a layout. In this case, we know we're going to
843 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000844 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
845 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000846 }
847
weinig@apple.com12840dc2013-10-22 23:59:08 +0000848 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
849 child.repaint();
850 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000851 }
852
853 if (paginated) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000854 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
855 fragmentedFlow->fragmentedFlowDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000856 // Check for an after page/column break.
857 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
858 if (newHeight != height())
859 setLogicalHeight(newHeight);
860 }
861
zalan@apple.com4de96c52017-11-07 04:09:59 +0000862 ASSERT(view().frameView().layoutContext().layoutDeltaMatches(oldLayoutDelta));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000863}
864
weinig@apple.com12840dc2013-10-22 23:59:08 +0000865void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000866{
867 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000868 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000869
870 LayoutUnit logicalTop = logicalHeight();
zalan@apple.com4d97a002016-02-24 17:13:33 +0000871 updateStaticInlinePositionForChild(child, logicalTop, DoNotIndentText);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000872
873 if (!marginInfo.canCollapseWithMarginBefore()) {
874 // Positioned blocks don't collapse margins, so add the margin provided by
875 // the container now. The child's own margin is added later when calculating its logical top.
876 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
877 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
878 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
879 }
880
weinig@apple.com12840dc2013-10-22 23:59:08 +0000881 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000882 if (childLayer->staticBlockPosition() != logicalTop) {
883 childLayer->setStaticBlockPosition(logicalTop);
884 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000885 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000886 }
887}
888
robert@webkit.org97037ef2013-11-20 19:26:10 +0000889LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
890{
891 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000892 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +0000893 if (parentBlock && RenderStyle::usedClear(*this) != UsedClear::None && parentBlock->getClearDelta(*this, logicalHeight()))
robert@webkit.org97037ef2013-11-20 19:26:10 +0000894 return marginValuesForChild(*this).positiveMarginBefore();
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +0000895 return 0_lu;
robert@webkit.org97037ef2013-11-20 19:26:10 +0000896}
897
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000898void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
899{
900 LayoutUnit startPosition = borderStart() + paddingStart();
heycam@apple.come5cd2832021-04-16 23:55:14 +0000901 if (shouldPlaceVerticalScrollbarOnLeft() && isHorizontalWritingMode())
mmaxfield@apple.comaf573be2016-03-12 21:18:25 +0000902 startPosition += (style().isLeftToRightDirection() ? 1 : -1) * verticalScrollbarWidth();
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000903 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
904
905 // Add in our start margin.
906 LayoutUnit childMarginStart = marginStartForChild(child);
907 LayoutUnit newPosition = startPosition + childMarginStart;
908
909 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
910 // to shift over as necessary to dodge any floats that might get in the way.
antti@apple.comeae76122017-09-20 15:37:23 +0000911 if (child.avoidsFloats() && containsFloats())
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000912 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
913
914 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
915}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000916
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000917void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
918{
919 // The float should be positioned taking into account the bottom margin
920 // of the previous flow. We add that margin into the height, get the
921 // float positioned properly, and then subtract the margin out of the
922 // height again. In the case of self-collapsing blocks, we always just
923 // use the top margins, since the self-collapsing block collapsed its
924 // own bottom margin into its top margin.
925 //
926 // Note also that the previous flow may collapse its margin into the top of
927 // our block. If this is the case, then we do not add the margin in to our
928 // height when computing the position of the float. This condition can be tested
929 // for by simply calling canCollapseWithMarginBefore. See
930 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
931 // an example of this scenario.
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +0000932 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0_lu : marginInfo.margin();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000933 setLogicalHeight(logicalHeight() + marginOffset);
934 positionNewFloats();
935 setLogicalHeight(logicalHeight() - marginOffset);
936}
937
zalan@apple.com4d97a002016-02-24 17:13:33 +0000938void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000939{
akling@apple.com827be9c2013-10-29 02:58:43 +0000940 if (child.style().isOriginalDisplayInlineType())
antti@apple.comc6a9c732019-08-12 15:31:34 +0000941 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, shouldIndentText));
weinig@apple.com12840dc2013-10-22 23:59:08 +0000942 else
943 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
944}
945
946void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
947{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +0000948 if (enclosingFragmentedFlow()) {
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +0000949 // Shift the inline position to exclude the fragment offset.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000950 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
951 }
952 child.layer()->setStaticInlinePosition(inlinePosition);
953}
954
antti@apple.comc6a9c732019-08-12 15:31:34 +0000955LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, IndentTextOrNot shouldIndentText)
956{
957 TextAlignMode textAlign = style().textAlign();
958 bool shouldApplyIndentText = false;
959 switch (textAlign) {
960 case TextAlignMode::Left:
961 case TextAlignMode::WebKitLeft:
962 shouldApplyIndentText = style().isLeftToRightDirection();
963 break;
964 case TextAlignMode::Right:
965 case TextAlignMode::WebKitRight:
966 shouldApplyIndentText = !style().isLeftToRightDirection();
967 break;
968 case TextAlignMode::Start:
969 shouldApplyIndentText = true;
970 break;
971 default:
972 shouldApplyIndentText = false;
973 }
974 // <rdar://problem/15427571>
975 // https://bugs.webkit.org/show_bug.cgi?id=124522
976 // This quirk is for legacy content that doesn't work properly with the center positioning scheme
977 // being honored (e.g., epubs).
978 if (shouldApplyIndentText || settings().useLegacyTextAlignPositionedElementBehavior()) // FIXME: Handle TextAlignMode::End here
979 return startOffsetForLine(position, shouldIndentText);
980
981 // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here
982 float totalLogicalWidth = 0;
983 float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), DoNotIndentText);
984 float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), DoNotIndentText) - logicalLeft;
985
antti@apple.com443deba2021-06-01 13:58:23 +0000986 LegacyLineLayout::updateLogicalWidthForAlignment(*this, textAlign, nullptr, nullptr, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
antti@apple.comc6a9c732019-08-12 15:31:34 +0000987
988 if (!style().isLeftToRightDirection())
989 return LayoutUnit(logicalWidth() - logicalLeft);
990
991 return LayoutUnit(logicalLeft);
992}
993
weinig@apple.com12840dc2013-10-22 23:59:08 +0000994RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000995{
ross.kirsling@sony.combd744282018-11-18 03:14:31 +0000996 LayoutUnit childBeforePositive;
997 LayoutUnit childBeforeNegative;
998 LayoutUnit childAfterPositive;
999 LayoutUnit childAfterNegative;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001000
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00001001 LayoutUnit beforeMargin;
1002 LayoutUnit afterMargin;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001003
cdumez@apple.com5f02e632022-01-16 01:33:25 +00001004 auto* childRenderBlock = dynamicDowncast<RenderBlockFlow>(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001005
1006 // If the child has the same directionality as we do, then we can just return its
1007 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001008 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001009 if (childRenderBlock) {
1010 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
1011 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
1012 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
1013 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
1014 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001015 beforeMargin = child.marginBefore();
1016 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001017 }
weinig@apple.com12840dc2013-10-22 23:59:08 +00001018 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001019 // The child has a different directionality. If the child is parallel, then it's just
1020 // flipped relative to us. We can use the margins for the opposite edges.
1021 if (childRenderBlock) {
1022 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
1023 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
1024 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
1025 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
1026 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001027 beforeMargin = child.marginAfter();
1028 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001029 }
1030 } else {
1031 // The child is perpendicular to us, which means its margins don't collapse but are on the
1032 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
1033 beforeMargin = marginBeforeForChild(child);
1034 afterMargin = marginAfterForChild(child);
1035 }
1036
1037 // Resolve uncollapsing margins into their positive/negative buckets.
1038 if (beforeMargin) {
1039 if (beforeMargin > 0)
1040 childBeforePositive = beforeMargin;
1041 else
1042 childBeforeNegative = -beforeMargin;
1043 }
1044 if (afterMargin) {
1045 if (afterMargin > 0)
1046 childAfterPositive = afterMargin;
1047 else
1048 childAfterNegative = -afterMargin;
1049 }
1050
1051 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
1052}
1053
hyatt@apple.com72311dc2015-09-10 22:15:46 +00001054bool RenderBlockFlow::childrenPreventSelfCollapsing() const
1055{
1056 if (!childrenInline())
1057 return RenderBlock::childrenPreventSelfCollapsing();
1058
antti@apple.comae85e112017-08-31 23:27:02 +00001059 return hasLines();
hyatt@apple.com72311dc2015-09-10 22:15:46 +00001060}
1061
weinig@apple.com12840dc2013-10-22 23:59:08 +00001062LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001063{
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001064 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
1065}
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001066
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001067LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
1068{
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001069 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
1070 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
1071 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
ntim@apple.comacb16d42021-12-24 18:55:35 +00001072
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001073 // Get the four margin values for the child and cache them.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001074 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001075
1076 // Get our max pos and neg top margins.
1077 LayoutUnit posTop = childMargins.positiveMarginBefore();
1078 LayoutUnit negTop = childMargins.negativeMarginBefore();
1079
1080 // For self-collapsing blocks, collapse our bottom margins into our
1081 // top to get new posTop and negTop values.
1082 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +00001083 posTop = std::max(posTop, childMargins.positiveMarginAfter());
1084 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001085 }
ntim@apple.comacb16d42021-12-24 18:55:35 +00001086
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001087 if (marginInfo.canCollapseWithMarginBefore()) {
ntim@apple.comacb16d42021-12-24 18:55:35 +00001088 // This child is collapsing with the top of the
1089 // block. If it has larger margin values, then we need to update
1090 // our own maximal values.
1091 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
1092 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001093
ntim@apple.comacb16d42021-12-24 18:55:35 +00001094 // The minute any of the margins involved isn't a quirk, don't
1095 // collapse it away, even if the margin is smaller (www.webreference.com
1096 // has an example of this, a <dt> with 0.8em author-specified inside
1097 // a <dl> inside a <td>.
1098 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
1099 setHasMarginBeforeQuirk(false);
1100 marginInfo.setDeterminedMarginBeforeQuirk(true);
1101 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001102
ntim@apple.comacb16d42021-12-24 18:55:35 +00001103 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
1104 // We have no top margin and our top child has a quirky margin.
1105 // We will pick up this quirky margin and pass it through.
1106 // This deals with the <td><div><p> case.
1107 // Don't do this for a block that split two inlines though. You do
1108 // still apply margins in this case.
1109 setHasMarginBeforeQuirk(true);
1110 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001111 }
1112
1113 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001114 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001115
1116 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1117 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001118
1119 LayoutUnit clearanceForSelfCollapsingBlock;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001120
robert@webkit.org97037ef2013-11-20 19:26:10 +00001121 // 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
1122 // 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
1123 // 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 +00001124 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1125 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001126 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1127 }
1128
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001129 if (childIsSelfCollapsing) {
ntim@apple.comacb16d42021-12-24 18:55:35 +00001130 // This child has no height. We need to compute our
1131 // position before we collapse the child's margins together,
1132 // so that we can get an accurate position for the zero-height block.
1133 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1134 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1135 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001136
ntim@apple.comacb16d42021-12-24 18:55:35 +00001137 // Now collapse the child's margins together, which means examining our
1138 // bottom margin values as well.
1139 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1140 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1141
1142 if (!marginInfo.canCollapseWithMarginBefore()) {
1143 // We need to make sure that the position of the self-collapsing block
1144 // is correct, since it could have overflowing content
1145 // that needs to be positioned correctly (e.g., a block that
1146 // had a specified height of 0 but that actually had subcontent).
1147 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001148 }
1149 } else {
ntim@apple.comacb16d42021-12-24 18:55:35 +00001150 if (!marginInfo.atBeforeSideOfBlock() || (!marginInfo.canCollapseMarginBeforeWithChildren()
1151 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk()))) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001152 // We're collapsing with a previous sibling's margins and not
1153 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001154 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001155 logicalTop = logicalHeight();
1156 }
1157
ntim@apple.comacb16d42021-12-24 18:55:35 +00001158 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1159 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001160
1161 if (marginInfo.margin())
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001162 marginInfo.setHasMarginAfterQuirk(afterQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001163 }
ntim@apple.comacb16d42021-12-24 18:55:35 +00001164
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001165 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1166 // collapsed into the page edge.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001167 auto* layoutState = view().frameView().layoutContext().layoutState();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001168 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1169 && hasNextPage(beforeCollapseLogicalTop)) {
1170 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001171 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001172 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1173 }
1174
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001175 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001176 // 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
1177 // any floats from the parent will now overhang.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001178 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001179 LayoutUnit oldLogicalHeight = logicalHeight();
1180 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001181 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001182 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001183 setLogicalHeight(oldLogicalHeight);
1184
1185 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1186 // 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
1187 // floats in the parent that overhang |child|'s new logical top.
1188 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001189 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1190 child->setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001191 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001192
1193 return logicalTop;
1194}
1195
weinig@apple.com12840dc2013-10-22 23:59:08 +00001196LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001197{
1198 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1199 if (!heightIncrease)
1200 return yPos;
1201
weinig@apple.com12840dc2013-10-22 23:59:08 +00001202 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001203 // For self-collapsing blocks that clear, they can still collapse their
1204 // margins with following siblings. Reset the current margins to represent
1205 // the self-collapsing block's margins only.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001206 MarginValues childMargins = marginValuesForChild(child);
ntim@apple.comacb16d42021-12-24 18:55:35 +00001207 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1208 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001209
1210 // CSS2.1 states:
1211 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1212 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1213 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1214 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1215 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001216 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001217 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1218 wouldCollapseMarginsWithParent = false;
1219 }
1220 if (wouldCollapseMarginsWithParent)
1221 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1222
robert@webkit.org97037ef2013-11-20 19:26:10 +00001223 // 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
1224 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1225 // 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
1226 // margins can collapse at the correct vertical position.
1227 // 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
1228 // (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],
1229 // i.e., clearance = [height of float] - margin-top".
1230 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001231 } else
1232 // Increase our height by the amount we had to clear.
1233 setLogicalHeight(logicalHeight() + heightIncrease);
1234
1235 if (marginInfo.canCollapseWithMarginBefore()) {
1236 // We can no longer collapse with the top of the block since a clear
1237 // occurred. The empty blocks collapse into the cleared block.
1238 // FIXME: This isn't quite correct. Need clarification for what to do
1239 // if the height the cleared block is offset by is smaller than the
1240 // margins involved.
1241 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1242 marginInfo.setAtBeforeSideOfBlock(false);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001243 }
1244
robert@webkit.org97037ef2013-11-20 19:26:10 +00001245 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001246}
1247
ntim@apple.comacb16d42021-12-24 18:55:35 +00001248void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001249{
1250 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1251 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
ntim@apple.comacb16d42021-12-24 18:55:35 +00001252 if (document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody()))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001253 return;
1254
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001255 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001256 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1257 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001258
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001259 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001260 return;
1261
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001262 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001263 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001264 return;
1265
weinig@apple.com12840dc2013-10-22 23:59:08 +00001266 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001267 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1268 return;
1269
weinig@apple.com12840dc2013-10-22 23:59:08 +00001270 RenderBox* grandchildBox = childBlock.firstChildBox();
1271 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001272 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1273 break;
1274 }
1275
1276 // Give up if there is clearance on the box, since it probably won't collapse into us.
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00001277 if (!grandchildBox || RenderStyle::usedClear(*grandchildBox) != UsedClear::None)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001278 return;
1279
1280 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1281 if (grandchildBox->needsLayout()) {
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00001282 grandchildBox->computeAndSetBlockDirectionMargins(*this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001283 if (is<RenderBlock>(*grandchildBox)) {
1284 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1285 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1286 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001287 }
1288 }
1289
1290 // Collapse the margin of the grandchild box with our own to produce an estimate.
ntim@apple.comacb16d42021-12-24 18:55:35 +00001291 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001292}
1293
weinig@apple.com12840dc2013-10-22 23:59:08 +00001294LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001295{
1296 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1297 // relayout if there are intruding floats.
1298 LayoutUnit logicalTopEstimate = logicalHeight();
1299 if (!marginInfo.canCollapseWithMarginBefore()) {
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00001300 LayoutUnit positiveMarginBefore;
1301 LayoutUnit negativeMarginBefore;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001302 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001303 // Try to do a basic estimation of how the collapse is going to go.
ntim@apple.comacb16d42021-12-24 18:55:35 +00001304 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001305 } else {
1306 // Use the cached collapsed margin values from a previous layout. Most of the time they
1307 // will be right.
1308 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001309 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1310 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001311 }
1312
1313 // Collapse the result with our current margins.
ntim@apple.comacb16d42021-12-24 18:55:35 +00001314 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001315 }
1316
1317 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1318 // page.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001319 auto* layoutState = view().frameView().layoutContext().layoutState();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001320 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1321 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001322 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001323
1324 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
ntim@apple.comacb16d42021-12-24 18:55:35 +00001325
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001326 estimateWithoutPagination = logicalTopEstimate;
1327
1328 if (layoutState->isPaginated()) {
1329 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1330 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
ntim@apple.comacb16d42021-12-24 18:55:35 +00001331
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001332 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1333 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
ntim@apple.comacb16d42021-12-24 18:55:35 +00001334
cdumez@apple.come9437792014-10-08 23:33:43 +00001335 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1336 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001337 }
1338
1339 return logicalTopEstimate;
1340}
1341
1342void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1343{
1344 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001345 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1346 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001347 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001348
1349 if (!marginInfo.hasMarginAfterQuirk())
1350 setHasMarginAfterQuirk(false);
1351
1352 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1353 // We have no bottom margin and our last child has a quirky margin.
1354 // We will pick up this quirky margin and pass it through.
1355 // This deals with the <td><div><p> case.
1356 setHasMarginAfterQuirk(true);
1357 }
1358}
1359
1360void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1361{
1362 marginInfo.setAtAfterSideOfBlock(true);
1363
robert@webkit.org97037ef2013-11-20 19:26:10 +00001364 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1365 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1366 // to perform now is at the child's margin-top - so adjust our height to that position.
1367 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001368 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1369 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001370
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001371 // If we can't collapse with children then add in the bottom margin.
ntim@apple.comacb16d42021-12-24 18:55:35 +00001372 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1373 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001374 setLogicalHeight(logicalHeight() + marginInfo.margin());
ntim@apple.comacb16d42021-12-24 18:55:35 +00001375 }
1376
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001377 // Now add in our bottom border/padding.
1378 setLogicalHeight(logicalHeight() + afterSide);
1379
1380 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1381 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001382 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001383
1384 // Update our bottom collapsed margin info.
1385 setCollapsedBottomMargin(marginInfo);
1386}
1387
1388void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1389{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001390 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001391 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001392 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001393 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001394 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001395
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001396 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1397 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001398}
1399
1400void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1401{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001402 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001403 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001404 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001405 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001406 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001407
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001408 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1409 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001410}
1411
weinig@apple.com12840dc2013-10-22 23:59:08 +00001412static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001413{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001414 RenderBlock* curr = child.containingBlock();
1415 while (curr && curr != &child.view()) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001416 if (curr->isRenderFragmentedFlow())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001417 return true;
1418 if (curr->isFloatingOrOutOfFlowPositioned())
1419 return false;
1420 curr = curr->containingBlock();
1421 }
1422 return true;
1423}
1424
weinig@apple.com12840dc2013-10-22 23:59:08 +00001425LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001426{
1427 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001428 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1429 bool isInsideMulticolFlow = fragmentedFlow;
1430 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
zalan@apple.com7fd79ce2017-11-08 15:02:10 +00001431 bool checkPageBreaks = !checkColumnBreaks && view().frameView().layoutContext().layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001432 bool checkFragmentBreaks = false;
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00001433 bool checkBeforeAlways = (checkColumnBreaks && child.style().breakBefore() == BreakBetween::Column)
antti@apple.com52d83832017-09-20 12:58:45 +00001434 || (checkPageBreaks && alwaysPageBreak(child.style().breakBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001435 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001436 if (checkColumnBreaks) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001437 if (isInsideMulticolFlow)
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001438 checkFragmentBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001439 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001440 if (checkFragmentBreaks) {
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00001441 LayoutUnit offsetBreakAdjustment;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001442 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001443 return logicalOffset + offsetBreakAdjustment;
1444 }
1445 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1446 }
1447 return logicalOffset;
1448}
1449
weinig@apple.com12840dc2013-10-22 23:59:08 +00001450LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001451{
1452 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001453 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1454 bool isInsideMulticolFlow = fragmentedFlow;
1455 bool checkColumnBreaks = fragmentedFlow && fragmentedFlow->shouldCheckColumnBreaks();
zalan@apple.com7fd79ce2017-11-08 15:02:10 +00001456 bool checkPageBreaks = !checkColumnBreaks && view().frameView().layoutContext().layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001457 bool checkFragmentBreaks = false;
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00001458 bool checkAfterAlways = (checkColumnBreaks && child.style().breakAfter() == BreakBetween::Column)
antti@apple.com52d83832017-09-20 12:58:45 +00001459 || (checkPageBreaks && alwaysPageBreak(child.style().breakAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001460 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00001461 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0_lu : marginInfo.margin();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001462
1463 // So our margin doesn't participate in the next collapsing steps.
1464 marginInfo.clearMargin();
1465
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001466 if (checkColumnBreaks) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001467 if (isInsideMulticolFlow)
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001468 checkFragmentBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001469 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001470 if (checkFragmentBreaks) {
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00001471 LayoutUnit offsetBreakAdjustment;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001472 if (fragmentedFlow->addForcedFragmentBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001473 return logicalOffset + marginOffset + offsetBreakAdjustment;
1474 }
1475 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1476 }
1477 return logicalOffset;
1478}
1479
weinig@apple.com12840dc2013-10-22 23:59:08 +00001480LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001481{
cdumez@apple.com5f02e632022-01-16 01:33:25 +00001482 auto* childRenderBlock = dynamicDowncast<RenderBlock>(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001483
1484 if (estimateWithoutPagination != logicalTopAfterClear) {
1485 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1486 // position.
1487 setLogicalHeight(logicalTopAfterClear);
1488 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1489
weinig@apple.com12840dc2013-10-22 23:59:08 +00001490 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001491 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1492 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001493 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001494 }
1495
1496 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001497 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001498 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001499 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001500 }
1501
1502 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001503 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001504 }
1505
1506 LayoutUnit oldTop = logicalTopAfterClear;
1507
1508 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1509 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1510
1511 if (pageLogicalHeightForOffset(result)) {
1512 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001513 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001514 if (spaceShortage > 0) {
1515 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1516 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1517 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1518 // This should be improved, though, because here we just pretend that the child is
1519 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1520 // where there's no child content, border or padding. In other words, we risk stretching more
1521 // than necessary.
1522 setPageBreak(result, spaceShortage);
1523 }
1524 }
1525
simon.fraser@apple.come8ee49b2022-05-06 17:10:31 +00001526 if (child.shouldApplySizeContainment())
cathiechen@igalia.come80ce682021-05-11 12:49:46 +00001527 adjustSizeContainmentChildForPagination(child, result);
1528
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001529 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1530 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1531 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1532
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00001533 LayoutUnit paginationStrut;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001534 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1535 if (unsplittableAdjustmentDelta)
1536 paginationStrut = unsplittableAdjustmentDelta;
1537 else if (childRenderBlock && childRenderBlock->paginationStrut())
1538 paginationStrut = childRenderBlock->paginationStrut();
1539
1540 if (paginationStrut) {
1541 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1542 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1543 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1544 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1545 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1546 // and pushes to the next page anyway, so not too concerned about it.
1547 setPaginationStrut(result + paginationStrut);
1548 if (childRenderBlock)
1549 childRenderBlock->setPaginationStrut(0);
1550 } else
1551 result += paginationStrut;
1552 }
1553
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001554 // 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 +00001555 setLogicalHeight(logicalHeight() + (result - oldTop));
1556
1557 // Return the final adjusted logical top.
1558 return result;
1559}
1560
antti@apple.com903292a2021-06-02 16:20:15 +00001561static inline LayoutUnit calculateMinimumPageHeight(const RenderStyle& renderStyle, LegacyRootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001562{
1563 // We may require a certain minimum number of lines per page in order to satisfy
1564 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001565 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001566 if (lineCount > 1) {
antti@apple.com903292a2021-06-02 16:20:15 +00001567 LegacyRootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001568 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1569 line = line->prevRootBox();
1570
1571 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1572 // adjustLinePositionForPagination() for more details.
1573 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
antti@apple.com657a14e2020-10-29 15:51:07 +00001574 lineTop = std::min(line->lineBoxTop(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001575 }
1576 return lineBottom - lineTop;
1577}
1578
antti@apple.com903292a2021-06-02 16:20:15 +00001579static inline bool needsAppleMailPaginationQuirk(LegacyRootInlineBox& lineBox)
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001580{
zalan@apple.coma1cff3a2017-01-14 18:45:20 +00001581 auto& renderer = lineBox.renderer();
bfulgham@apple.com62729772015-04-29 02:26:07 +00001582
zalan@apple.coma1cff3a2017-01-14 18:45:20 +00001583 if (!renderer.settings().appleMailPaginationQuirkEnabled())
bfulgham@apple.com62729772015-04-29 02:26:07 +00001584 return false;
1585
cdumez@apple.com19105c12022-06-05 06:59:51 +00001586 if (renderer.element() && renderer.element()->idForStyleResolution() == "messageContentContainer"_s)
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001587 return true;
1588
1589 return false;
1590}
zalan@apple.come031dfb2016-08-25 18:41:22 +00001591
1592static void clearShouldBreakAtLineToAvoidWidowIfNeeded(RenderBlockFlow& blockFlow)
1593{
1594 if (!blockFlow.shouldBreakAtLineToAvoidWidow())
1595 return;
1596 blockFlow.clearShouldBreakAtLineToAvoidWidow();
1597 blockFlow.setDidBreakAtLineToAvoidWidow();
1598}
1599
antti@apple.com903292a2021-06-02 16:20:15 +00001600void RenderBlockFlow::adjustLinePositionForPagination(LegacyRootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsFragment, RenderFragmentedFlow* fragmentedFlow)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001601{
1602 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1603 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1604 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1605 // of the first column.
1606 //
1607 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1608 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1609 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1610 // for overflow to occur), and then cache visible overflow for each column rect.
1611 //
1612 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1613 // content that paints in a previous column (and content that paints in the following column).
1614 //
1615 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1616 // at least make positive leading work in typical cases.
1617 //
1618 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1619 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1620 // line and all following lines.
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001621 overflowsFragment = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001622 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
antti@apple.com657a14e2020-10-29 15:51:07 +00001623 LayoutUnit logicalOffset = std::min(lineBox->lineBoxTop(), logicalVisualOverflow.y());
1624 LayoutUnit logicalBottom = std::max(lineBox->lineBoxBottom(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001625 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001626 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001627 logicalOffset += delta;
1628 lineBox->setPaginationStrut(0);
1629 lineBox->setIsFirstAfterPageBreak(false);
1630 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001631 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001632 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1633 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001634 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001635 // 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.
1636 // 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.
zalan@apple.com3b1271d2020-03-25 01:46:09 +00001637 // With no valid page height, we can't possibly accommodate the widow rules.
1638 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001639 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001640 }
1641
1642 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1643 // 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
1644 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1645 // 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
1646 // top of the page.
1647 // 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
1648 // this will be a real-world issue. For now we don't try to deal with this problem.
basuke.suzuki@sony.com5ecd9752021-04-21 01:42:52 +00001649 logicalOffset = static_cast<float>(intMaxForLayoutUnit);
1650 logicalBottom = static_cast<float>(intMinForLayoutUnit);
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001651 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1652 lineHeight = logicalBottom - logicalOffset;
zalan@apple.come031dfb2016-08-25 18:41:22 +00001653 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) {
1654 // Give up. We're genuinely too big even after excluding blank space and overflow.
1655 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
1656 return;
1657 }
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001658 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1659 }
1660
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001661 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001662 overflowsFragment = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001663
antti@apple.com443deba2021-06-01 13:58:23 +00001664 int lineIndex = legacyLineLayout()->lineCountUntil(lineBox);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001665 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
zalan@apple.come031dfb2016-08-25 18:41:22 +00001666 if (lineBreakToAvoidWidow() == lineIndex)
1667 clearShouldBreakAtLineToAvoidWidowIfNeeded(*this);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001668 // If we have a non-uniform page height, then we have to shift further possibly.
1669 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1670 return;
1671 if (lineHeight > pageLogicalHeight) {
1672 // Split the top margin in order to avoid splitting the visible part of the line.
antti@apple.com657a14e2020-10-29 15:51:07 +00001673 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineBoxTop()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001674 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001675 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001676 overflowsFragment = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001677 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001678 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1679 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001680 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001681 && !isOutOfFlowPositioned() && !isTableCell()) {
1682 auto firstRootBox = this->firstRootBox();
commit-queue@webkit.orge2d17aa2020-01-30 18:07:10 +00001683 if (!firstRootBox) {
1684 setPaginationStrut(remainingLogicalHeight + logicalOffset);
1685 return;
1686 }
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001687 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00001688 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), 0_lu);
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001689 if (needsAppleMailPaginationQuirk(*lineBox))
1690 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001691 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1692 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001693 delta += remainingLogicalHeight;
1694 lineBox->setPaginationStrut(remainingLogicalHeight);
1695 lineBox->setIsFirstAfterPageBreak(true);
1696 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001697 } else if (remainingLogicalHeight == pageLogicalHeight) {
1698 // We're at the very top of a page or column.
1699 if (lineBox != firstRootBox())
1700 lineBox->setIsFirstAfterPageBreak(true);
1701 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1702 setPageBreak(logicalOffset, lineHeight);
1703 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001704}
1705
1706void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1707{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001708 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001709 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1710 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001711}
1712
abucur@adobe.comfc497132013-10-04 08:49:21 +00001713void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1714{
1715 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001716 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001717 return;
1718
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001719 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001720}
1721
1722void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1723{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001724 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001725 return;
1726
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001727 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001728}
1729
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001730void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1731{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001732 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001733 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001734 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001735
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001736 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001737}
1738
weinig@apple.com31324fd2013-10-28 19:22:51 +00001739bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1740{
zalan@apple.com4de96c52017-11-07 04:09:59 +00001741 ASSERT(view().frameView().layoutContext().layoutState() && view().frameView().layoutContext().layoutState()->isPaginated());
weinig@apple.com31324fd2013-10-28 19:22:51 +00001742
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001743 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1744 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001745 return true; // Printing and multi-column both make new pages to accommodate content.
1746
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001747 // See if we're in the last fragment.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001748 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001749 RenderFragmentContainer* fragment = fragmentedFlow->fragmentAtBlockOffset(this, pageOffset, true);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001750 if (!fragment)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001751 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001752
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001753 if (fragment->isLastFragment())
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001754 return fragment->isRenderFragmentContainerSet() || (pageBoundaryRule == IncludePageBoundary && pageOffset == fragment->logicalTopForFragmentedFlowContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001755
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001756 RenderFragmentContainer* startFragment = nullptr;
1757 RenderFragmentContainer* endFragment = nullptr;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001758 fragmentedFlow->getFragmentRangeForBox(this, startFragment, endFragment);
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001759 return (endFragment && fragment != endFragment);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001760}
1761
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001762LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, LayoutUnit childBeforeMargin, LayoutUnit childAfterMargin)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001763{
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001764 // When flexboxes are embedded inside a block flow, they don't perform any adjustments for unsplittable
1765 // children. We'll treat flexboxes themselves as unsplittable just to get them to paginate properly inside
1766 // a block flow.
1767 bool isUnsplittable = childBoxIsUnsplittableForFragmentation(child);
1768 if (!isUnsplittable && !(child.isFlexibleBox() && !downcast<RenderFlexibleBox>(child).isFlexibleBoxImpl()))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001769 return logicalOffset;
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001770
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001771 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001772 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + childBeforeMargin + childAfterMargin;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001773 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001774 bool hasUniformPageLogicalHeight = !fragmentedFlow || fragmentedFlow->fragmentsHaveUniformLogicalHeight();
hyatt@apple.com531e35d2017-04-13 16:37:00 +00001775 if (isUnsplittable)
1776 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001777 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1778 || !hasNextPage(logicalOffset))
1779 return logicalOffset;
1780 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1781 if (remainingLogicalHeight < childLogicalHeight) {
1782 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1783 return logicalOffset;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001784 auto result = logicalOffset + remainingLogicalHeight;
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00001785 bool isInitialLetter = child.isFloating() && child.style().styleType() == PseudoId::FirstLetter && child.style().initialLetterDrop() > 0;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001786 if (isInitialLetter) {
1787 // Increase our logical height to ensure that lines all get pushed along with the letter.
1788 setLogicalHeight(logicalOffset + remainingLogicalHeight);
1789 }
1790 return result;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001791 }
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00001792
weinig@apple.com31324fd2013-10-28 19:22:51 +00001793 return logicalOffset;
1794}
1795
1796bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1797{
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001798 bool checkFragment = false;
zalan@apple.com065b9d02020-04-03 13:56:32 +00001799 auto* fragmentedFlow = enclosingFragmentedFlow();
1800 RenderFragmentContainer* currentFragmentContainer = nullptr;
1801 for (auto pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight; pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
weinig@apple.com31324fd2013-10-28 19:22:51 +00001802 if (minimumLogicalHeight <= pageLogicalHeight)
1803 return true;
zalan@apple.com065b9d02020-04-03 13:56:32 +00001804 auto adjustedOffset = logicalOffset + adjustment;
1805 if (!hasNextPage(adjustedOffset))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001806 return false;
zalan@apple.com065b9d02020-04-03 13:56:32 +00001807 if (fragmentedFlow) {
1808 // While in layout and the columnsets are not balanced yet, we keep finding the same (infinite tall) column over and over again.
1809 auto* nextFragmentContainer = fragmentedFlow->fragmentAtBlockOffset(this, adjustedOffset, true);
1810 ASSERT(nextFragmentContainer);
1811 if (nextFragmentContainer == currentFragmentContainer)
1812 return false;
1813 currentFragmentContainer = nextFragmentContainer;
1814 }
weinig@apple.com31324fd2013-10-28 19:22:51 +00001815 adjustment += pageLogicalHeight;
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001816 checkFragment = true;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001817 }
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00001818 return !checkFragment;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001819}
1820
1821void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1822{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001823 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1824 fragmentedFlow->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001825}
1826
1827void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1828{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001829 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1830 fragmentedFlow->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001831}
1832
1833LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1834{
1835 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1836 if (!pageLogicalHeight)
1837 return logicalOffset;
1838
1839 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1840 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1841 if (pageBoundaryRule == ExcludePageBoundary)
1842 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1843 return logicalOffset + remainingLogicalHeight;
1844}
1845
1846LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1847{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001848 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1849 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
zalan@apple.com4de96c52017-11-07 04:09:59 +00001850 auto* layoutState = view().frameView().layoutContext().layoutState();
zalan@apple.com7fd79ce2017-11-08 15:02:10 +00001851 LayoutUnit pageLogicalHeight = layoutState->pageLogicalHeight();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001852 if (!pageLogicalHeight)
1853 return 0;
1854
zalan@apple.com7fd79ce2017-11-08 15:02:10 +00001855 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? layoutState->pageOffset().height() : layoutState->pageOffset().width();
1856 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? layoutState->layoutOffset().height() : layoutState->layoutOffset().width();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001857
1858 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001859 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1860 if (!fragmentedFlow)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001861 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001862 return firstPageLogicalTop + fragmentedFlow->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001863}
1864
1865LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1866{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001867 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1868 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
zalan@apple.com7fd79ce2017-11-08 15:02:10 +00001869 LayoutUnit pageLogicalHeight = view().frameView().layoutContext().layoutState()->pageLogicalHeight();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001870 if (!pageLogicalHeight)
1871 return 0;
1872
1873 // Now check for a flow thread.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001874 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1875 if (!fragmentedFlow)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001876 return pageLogicalHeight;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001877 return fragmentedFlow->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
weinig@apple.com31324fd2013-10-28 19:22:51 +00001878}
1879
1880LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1881{
1882 offset += offsetFromLogicalTopOfFirstPage();
1883
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001884 RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow();
1885 if (!fragmentedFlow) {
zalan@apple.com7fd79ce2017-11-08 15:02:10 +00001886 LayoutUnit pageLogicalHeight = view().frameView().layoutContext().layoutState()->pageLogicalHeight();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001887 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1888 if (pageBoundaryRule == IncludePageBoundary) {
1889 // If includeBoundaryPoint is true the line exactly on the top edge of a
1890 // column will act as being part of the previous column.
1891 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1892 }
1893 return remainingHeight;
1894 }
1895
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00001896 return fragmentedFlow->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001897}
1898
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001899LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1900{
antti@apple.comeae76122017-09-20 15:37:23 +00001901 return logicalHeightForChild(child);
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001902}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001903
cathiechen@igalia.come80ce682021-05-11 12:49:46 +00001904void RenderBlockFlow::adjustSizeContainmentChildForPagination(RenderBox& child, LayoutUnit offset)
1905{
simon.fraser@apple.come8ee49b2022-05-06 17:10:31 +00001906 if (!child.shouldApplySizeContainment())
cathiechen@igalia.come80ce682021-05-11 12:49:46 +00001907 return;
1908
1909 LayoutUnit childOverflowHeight = child.isHorizontalWritingMode() ? child.layoutOverflowRect().maxY() : child.layoutOverflowRect().maxX();
1910 LayoutUnit childLogicalHeight = std::max(child.logicalHeight(), childOverflowHeight);
1911
1912 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(offset, ExcludePageBoundary);
1913
1914 LayoutUnit spaceShortage = childLogicalHeight - remainingLogicalHeight;
1915 if (spaceShortage <= 0)
1916 return;
1917
1918 if (RenderFragmentedFlow* fragmentedFlow = enclosingFragmentedFlow())
1919 fragmentedFlow->updateSpaceShortageForSizeContainment(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1920}
1921
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001922void RenderBlockFlow::layoutLineGridBox()
1923{
akling@apple.com827be9c2013-10-29 02:58:43 +00001924 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001925 setLineGridBox(0);
1926 return;
1927 }
1928
1929 setLineGridBox(0);
1930
antti@apple.com903292a2021-06-02 16:20:15 +00001931 auto lineGridBox = makeUnique<LegacyRootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001932 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1933 lineGridBox->setConstructed();
1934 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1935 VerticalPositionCache verticalPositionCache;
1936 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1937
aestes@apple.com13aae082016-01-02 08:03:08 +00001938 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001939
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001940 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1941 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1942 // to this grid.
1943}
1944
weinig@apple.com12840dc2013-10-22 23:59:08 +00001945bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001946{
commit-queue@webkit.orgc27f5ca2018-11-26 19:29:23 +00001947 return m_floatingObjects && m_floatingObjects->set().contains<FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001948}
1949
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001950bool RenderBlockFlow::subtreeContainsFloat(RenderBox& renderer) const
1951{
commit-queue@webkit.org7fa28a62022-01-07 19:34:59 +00001952 if (containsFloat(renderer))
1953 return true;
1954
1955 for (auto& block : descendantsOfType<RenderBlock>(const_cast<RenderBlockFlow&>(*this))) {
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001956 if (!is<RenderBlockFlow>(block))
1957 continue;
1958 auto& blockFlow = downcast<RenderBlockFlow>(block);
commit-queue@webkit.org7fa28a62022-01-07 19:34:59 +00001959 if (blockFlow.containsFloat(renderer))
1960 return true;
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001961 }
commit-queue@webkit.org7fa28a62022-01-07 19:34:59 +00001962
1963 return false;
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001964}
1965
1966bool RenderBlockFlow::subtreeContainsFloats() const
1967{
commit-queue@webkit.org7fa28a62022-01-07 19:34:59 +00001968 if (containsFloats())
1969 return true;
1970
1971 for (auto& block : descendantsOfType<RenderBlock>(const_cast<RenderBlockFlow&>(*this))) {
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001972 if (!is<RenderBlockFlow>(block))
1973 continue;
1974 auto& blockFlow = downcast<RenderBlockFlow>(block);
commit-queue@webkit.org7fa28a62022-01-07 19:34:59 +00001975 if (blockFlow.containsFloats())
1976 return true;
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001977 }
commit-queue@webkit.org7fa28a62022-01-07 19:34:59 +00001978
1979 return false;
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00001980}
1981
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001982void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1983{
1984 RenderBlock::styleDidChange(diff, oldStyle);
1985
1986 // After our style changed, if we lose our ability to propagate floats into next sibling
1987 // blocks, then we need to find the top most parent containing that overhanging float and
1988 // then mark its descendants with floats for layout and clear all floats from its next
1989 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1990 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
commit-queue@webkit.org1a4e6672018-05-21 16:55:45 +00001991 if (diff == StyleDifference::Layout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001992 RenderBlockFlow* parentBlock = this;
1993 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001994
weinig@apple.comc77041e2013-12-14 18:05:45 +00001995 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
1996 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00001997 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00001998 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00001999 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2000 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002001 if (ancestor.hasOverhangingFloat(renderer)) {
2002 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002003 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002004 }
2005 }
2006 }
2007 }
2008
2009 parentBlock->markAllDescendantsWithFloatsForLayout();
2010 parentBlock->markSiblingsWithFloatsForLayout();
2011 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002012
commit-queue@webkit.org1a4e6672018-05-21 16:55:45 +00002013 if (diff >= StyleDifference::Repaint) {
zalan@apple.comd4880dc2020-01-05 15:13:08 +00002014 auto shouldInvalidateLineLayoutPath = [&] {
antti@apple.com443deba2021-06-01 13:58:23 +00002015 if (selfNeedsLayout() || legacyLineLayout())
zalan@apple.comd4880dc2020-01-05 15:13:08 +00002016 return true;
zalan@apple.comd4880dc2020-01-05 15:13:08 +00002017#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00002018 if (modernLineLayout() && !LayoutIntegration::LineLayout::canUseForAfterStyleChange(*this, diff))
zalan@apple.comd4880dc2020-01-05 15:13:08 +00002019 return true;
2020#endif
2021 return false;
2022 };
2023 if (shouldInvalidateLineLayoutPath())
antti@apple.com9e891c82014-05-22 06:12:34 +00002024 invalidateLineLayoutPath();
antti@apple.comaf907312021-09-04 13:20:39 +00002025 }
antti@apple.com2943bef2020-10-21 16:21:04 +00002026
2027#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.comaf907312021-09-04 13:20:39 +00002028 if (auto* lineLayout = modernLineLayout())
zalan@apple.com0afc6332021-09-17 15:03:12 +00002029 lineLayout->updateStyle(*this, *oldStyle);
antti@apple.com2943bef2020-10-21 16:21:04 +00002030#endif
antti@apple.com9e891c82014-05-22 06:12:34 +00002031
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002032 if (multiColumnFlow())
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002033 updateStylesForColumnChildren();
2034}
2035
2036void RenderBlockFlow::updateStylesForColumnChildren()
2037{
zalan@apple.comcffcdb42021-04-28 16:54:01 +00002038 for (auto* child = firstChildBox(); child && (child->isRenderFragmentedFlow() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00002039 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), DisplayType::Block));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002040}
2041
akling@apple.combdae43242013-10-25 12:00:20 +00002042void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002043{
akling@apple.com827be9c2013-10-29 02:58:43 +00002044 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002045 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2046
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002047 if (oldStyle) {
commit-queue@webkit.org1a4e6672018-05-21 16:55:45 +00002048 auto oldPosition = oldStyle->position();
2049 auto newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002050
commit-queue@webkit.org1a4e6672018-05-21 16:55:45 +00002051 if (parent() && diff == StyleDifference::Layout && oldPosition != newPosition) {
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002052 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2053 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002054 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002055 }
2056
2057 RenderBlock::styleWillChange(diff, newStyle);
2058}
2059
antti@apple.coma2c7f242013-10-22 22:37:25 +00002060void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002061{
commit-queue@webkit.org1acd7232021-10-12 20:43:49 +00002062 m_lineLayout = std::monostate();
weinig@apple.com611b9292013-10-20 22:57:54 +00002063
antti@apple.coma2c7f242013-10-22 22:37:25 +00002064 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002065}
2066
zalan@apple.com232b0932016-12-24 18:00:00 +00002067void RenderBlockFlow::addFloatsToNewParent(RenderBlockFlow& toBlockFlow) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002068{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002069 // When a portion of the render tree is being detached, anonymous blocks
2070 // will be combined as their children are deleted. In this process, the
2071 // anonymous block later in the tree is merged into the one preceeding it.
2072 // It can happen that the later block (this) contains floats that the
2073 // previous block (toBlockFlow) did not contain, and thus are not in the
2074 // floating objects list for toBlockFlow. This can result in toBlockFlow
2075 // containing floats that are not in it's floating objects list, but are in
2076 // the floating objects lists of siblings and parents. This can cause
2077 // problems when the float itself is deleted, since the deletion code
2078 // assumes that if a float is not in it's containing block's floating
2079 // objects list, it isn't in any floating objects list. In order to
2080 // preserve this condition (removing it has serious performance
2081 // implications), we need to copy the floating objects from the old block
2082 // (this) to the new block (toBlockFlow). The float's metrics will likely
2083 // all be wrong, but since toBlockFlow is already marked for layout, this
2084 // will get fixed before anything gets displayed.
2085 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
zalan@apple.com232b0932016-12-24 18:00:00 +00002086 if (!m_floatingObjects)
2087 return;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002088
zalan@apple.com232b0932016-12-24 18:00:00 +00002089 if (!toBlockFlow.m_floatingObjects)
2090 toBlockFlow.createFloatingObjects();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002091
zalan@apple.com26018542017-03-30 01:25:00 +00002092 for (auto& floatingObject : m_floatingObjects->set()) {
2093 if (toBlockFlow.containsFloat(floatingObject->renderer()))
2094 continue;
zalan@apple.com232b0932016-12-24 18:00:00 +00002095 toBlockFlow.m_floatingObjects->add(floatingObject->cloneForNewParent());
zalan@apple.com26018542017-03-30 01:25:00 +00002096 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002097}
2098
2099void RenderBlockFlow::addOverflowFromFloats()
2100{
2101 if (!m_floatingObjects)
2102 return;
2103
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002104 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2105 auto end = floatingObjectSet.end();
2106 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002107 const auto& floatingObject = *it->get();
2108 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002109 addOverflowFromChild(&floatingObject.renderer(), floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002110 }
2111}
2112
2113void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2114{
2115 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2116
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002117 if (!multiColumnFlow() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002118 addOverflowFromFloats();
2119}
2120
2121void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2122{
2123 // Repaint any overhanging floats (if we know we're the one to paint them).
2124 // Otherwise, bail out.
2125 if (!hasOverhangingFloats())
2126 return;
2127
2128 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2129 // in this block. Better yet would be to push extra state for the containers of other floats.
zalan@apple.com4de96c52017-11-07 04:09:59 +00002130 LayoutStateDisabler layoutStateDisabler(view().frameView().layoutContext());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002131 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2132 auto end = floatingObjectSet.end();
2133 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002134 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002135 // Only repaint the object if it is overhanging, is not in its own layer, and
2136 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2137 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002138 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002139 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002140 && !renderer.hasSelfPaintingLayer()
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002141 && (floatingObject.paintsFloat() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002142 renderer.repaint();
2143 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002144 }
2145 }
2146}
2147
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002148void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002149{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002150 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002151
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002152 if (!multiColumnFlow() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002153 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002154
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002155 // Iterate over our children and paint the column rules as needed.
2156 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
zalan@apple.com16a404e2022-02-20 14:17:30 +00002157 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(columnSet, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002158 columnSet.paintColumnRules(paintInfo, childPoint);
2159 }
2160}
2161
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002162void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2163{
2164 if (!m_floatingObjects)
2165 return;
2166
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002167 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2168 auto end = floatingObjectSet.end();
2169 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002170 const auto& floatingObject = *it->get();
2171 auto& renderer = floatingObject.renderer();
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002172 if (floatingObject.shouldPaint()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002173 PaintInfo currentPaintInfo(paintInfo);
achristensen@apple.com9a618a92018-08-06 20:41:05 +00002174 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhase::BlockBackground;
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002175 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, paintOffset + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002176 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002177 if (!preservePhase) {
achristensen@apple.com9a618a92018-08-06 20:41:05 +00002178 currentPaintInfo.phase = PaintPhase::ChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002179 renderer.paint(currentPaintInfo, childPoint);
achristensen@apple.com9a618a92018-08-06 20:41:05 +00002180 currentPaintInfo.phase = PaintPhase::Float;
zalan@apple.com6816b132015-10-17 19:14:53 +00002181 renderer.paint(currentPaintInfo, childPoint);
achristensen@apple.com9a618a92018-08-06 20:41:05 +00002182 currentPaintInfo.phase = PaintPhase::Foreground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002183 renderer.paint(currentPaintInfo, childPoint);
achristensen@apple.com9a618a92018-08-06 20:41:05 +00002184 currentPaintInfo.phase = PaintPhase::Outline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002185 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002186 }
2187 }
2188 }
2189}
2190
weinig@apple.com12840dc2013-10-22 23:59:08 +00002191void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002192{
2193 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002194 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2195 auto end = floatingObjectSet.end();
2196 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002197 const auto& floatingObject = *it->get();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002198 LayoutRect floatBox(offsetFromRootBlock.width(), offsetFromRootBlock.height(), floatingObject.renderer().width(), floatingObject.renderer().height());
2199 floatBox.move(floatingObject.locationOffsetOfBorderBox());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002200 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002201 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002202 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002203 }
2204 }
2205}
2206
2207void RenderBlockFlow::createFloatingObjects()
2208{
ysuzuki@apple.com1d8e24d2019-08-19 06:59:40 +00002209 m_floatingObjects = makeUnique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002210}
2211
2212void RenderBlockFlow::removeFloatingObjects()
2213{
2214 if (!m_floatingObjects)
2215 return;
2216
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002217 markSiblingsWithFloatsForLayout();
2218
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002219 m_floatingObjects->clear();
2220}
2221
weinig@apple.com12840dc2013-10-22 23:59:08 +00002222FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002223{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002224 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002225
2226 // Create the list of special objects if we don't aleady have one
2227 if (!m_floatingObjects)
2228 createFloatingObjects();
2229 else {
2230 // Don't insert the floatingObject again if it's already in the list
2231 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
commit-queue@webkit.orgc27f5ca2018-11-26 19:29:23 +00002232 auto it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002233 if (it != floatingObjectSet.end())
2234 return it->get();
2235 }
2236
2237 // Create the special floatingObject entry & append it to the list
2238
weinig@apple.com12840dc2013-10-22 23:59:08 +00002239 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002240
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002241 // 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 +00002242 bool isChildRenderBlock = floatBox.isRenderBlock();
zalan@apple.com4de96c52017-11-07 04:09:59 +00002243 if (isChildRenderBlock && !floatBox.needsLayout() && view().frameView().layoutContext().layoutState()->pageLogicalHeightChanged())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002244 floatBox.setChildNeedsLayout(MarkOnlyThis);
zalan@apple.com4de96c52017-11-07 04:09:59 +00002245
2246 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().frameView().layoutContext().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002247 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2248 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002249 floatBox.layoutIfNeeded();
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002250 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002251 floatBox.updateLogicalWidth();
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00002252 floatBox.computeAndSetBlockDirectionMargins(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002253 }
2254
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002255 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002256
aestes@apple.com13aae082016-01-02 08:03:08 +00002257 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002258}
2259
weinig@apple.com12840dc2013-10-22 23:59:08 +00002260void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002261{
2262 if (m_floatingObjects) {
2263 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
commit-queue@webkit.orgc27f5ca2018-11-26 19:29:23 +00002264 auto it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002265 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002266 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002267 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002268 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2269 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002270
2271 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2272 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2273 logicalBottom = LayoutUnit::max();
2274 else {
2275 // Special-case zero- and less-than-zero-height floats: those don't touch
2276 // the line that they're on, but it still needs to be dirtied. This is
2277 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002278 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002279 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002280 if (floatingObject.originatingLine()) {
2281 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002282 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002283 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2284 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002285 }
mark.lam@apple.com65724362020-01-06 22:24:50 +00002286#if ASSERT_ENABLED
zalan@apple.comd2acead2017-09-20 22:03:06 +00002287 floatingObject.clearOriginatingLine();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002288#endif
2289 }
2290 markLinesDirtyInBlockRange(0, logicalBottom);
2291 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002292 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002293 }
2294 }
2295}
2296
2297void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2298{
2299 if (!containsFloats())
2300 return;
2301
2302 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2303 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002304 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002305 m_floatingObjects->remove(curr);
2306 if (floatingObjectSet.isEmpty())
2307 break;
2308 curr = floatingObjectSet.last().get();
2309 }
2310}
2311
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002312LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2313{
2314 LayoutUnit offset = fixedOffset;
2315 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2316 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2317 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2318}
2319
2320LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2321{
2322 LayoutUnit offset = fixedOffset;
2323 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2324 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2325 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2326}
2327
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002328void RenderBlockFlow::computeLogicalLocationForFloat(FloatingObject& floatingObject, LayoutUnit& logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002329{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002330 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002331 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002332 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002333
andersca@apple.com86298632013-11-10 19:32:33 +00002334 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002335
2336 LayoutUnit floatLogicalLeft;
2337
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002338 bool insideFragmentedFlow = enclosingFragmentedFlow();
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00002339 bool isInitialLetter = childBox.style().styleType() == PseudoId::FirstLetter && childBox.style().initialLetterDrop() > 0;
hyatt@apple.com87515262014-09-04 21:20:12 +00002340
2341 if (isInitialLetter) {
2342 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2343 if (letterClearance > 0) {
2344 logicalTopOffset += letterClearance;
2345 setLogicalHeight(logicalHeight() + letterClearance);
2346 }
2347 }
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002348
2349 if (RenderStyle::usedFloat(childBox) == UsedFloat::Left) {
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00002350 LayoutUnit heightRemainingLeft = 1_lu;
2351 LayoutUnit heightRemainingRight = 1_lu;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002352 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2353 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002354 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002355 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002356 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002357 // Have to re-evaluate all of our offsets, since they may have changed.
2358 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2359 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002360 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002361 }
2362 }
andersca@apple.com86298632013-11-10 19:32:33 +00002363 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002364 } else {
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00002365 LayoutUnit heightRemainingLeft = 1_lu;
2366 LayoutUnit heightRemainingRight = 1_lu;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002367 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2368 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002369 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002370 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00002371 if (insideFragmentedFlow) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002372 // Have to re-evaluate all of our offsets, since they may have changed.
2373 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2374 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002375 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002376 }
2377 }
2378 // Use the original width of the float here, since the local variable
2379 // |floatLogicalWidth| was capped to the available line width. See
2380 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002381 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002382 }
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002383
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002384 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
2385 LayoutUnit childBeforeMargin = marginBeforeForChild(childBox);
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002386
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002387 if (isInitialLetter)
2388 adjustInitialLetterPosition(childBox, logicalTopOffset, childBeforeMargin);
2389
2390 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
2391 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
2392
2393 setLogicalTopForFloat(floatingObject, logicalTopOffset);
2394 setLogicalTopForChild(childBox, logicalTopOffset + childBeforeMargin);
2395
2396 setLogicalMarginsForFloat(floatingObject, childLogicalLeftMargin, childBeforeMargin);
2397}
2398
2399void RenderBlockFlow::adjustInitialLetterPosition(RenderBox& childBox, LayoutUnit& logicalTopOffset, LayoutUnit& marginBeforeOffset)
2400{
2401 const RenderStyle& style = firstLineStyle();
mmaxfield@apple.com881a9362022-02-02 05:12:47 +00002402 const FontMetrics& fontMetrics = style.metricsOfPrimaryFont();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002403 if (!fontMetrics.hasCapHeight())
2404 return;
2405
2406 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2407 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2408
2409 // Make an adjustment to align with the cap height of a theoretical block line.
2410 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2411 logicalTopOffset += adjustment;
2412
2413 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2414 // positive for raised and negative for sunken).
2415 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2416
2417 // 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.
2418 if (dropHeightDelta < 0)
2419 marginBeforeOffset += -dropHeightDelta * heightOfLine;
2420
2421 // 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
2422 // empty lines beside the first letter.
2423 if (dropHeightDelta > 0)
2424 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002425}
2426
2427bool RenderBlockFlow::positionNewFloats()
2428{
2429 if (!m_floatingObjects)
2430 return false;
2431
2432 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2433 if (floatingObjectSet.isEmpty())
2434 return false;
2435
2436 // If all floats have already been positioned, then we have no work to do.
2437 if (floatingObjectSet.last()->isPlaced())
2438 return false;
2439
2440 // Move backwards through our floating object list until we find a float that has
2441 // already been positioned. Then we'll be able to move forward, positioning all of
2442 // the new floats that need it.
2443 auto it = floatingObjectSet.end();
2444 --it; // Go to last item.
2445 auto begin = floatingObjectSet.begin();
2446 FloatingObject* lastPlacedFloatingObject = 0;
2447 while (it != begin) {
2448 --it;
2449 if ((*it)->isPlaced()) {
2450 lastPlacedFloatingObject = it->get();
2451 ++it;
2452 break;
2453 }
2454 }
2455
2456 LayoutUnit logicalTop = logicalHeight();
2457
2458 // The float cannot start above the top position of the last positioned float.
2459 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002460 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002461
2462 auto end = floatingObjectSet.end();
2463 // Now walk through the set of unpositioned floats and place them.
2464 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002465 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002466 // The containing block is responsible for positioning floats, so if we have floats in our
2467 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002468 auto& childBox = floatingObject.renderer();
2469 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002470 continue;
2471
weinig@apple.com12840dc2013-10-22 23:59:08 +00002472 LayoutRect oldRect = childBox.frameRect();
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002473 auto childBoxUsedClear = RenderStyle::usedClear(childBox);
2474 if (childBoxUsedClear == UsedClear::Left || childBoxUsedClear == UsedClear::Both)
andersca@apple.com86298632013-11-10 19:32:33 +00002475 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002476 if (childBoxUsedClear == UsedClear::Right || childBoxUsedClear == UsedClear::Both)
andersca@apple.com86298632013-11-10 19:32:33 +00002477 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002478
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002479 computeLogicalLocationForFloat(floatingObject, logicalTop);
2480 LayoutUnit childLogicalTop = logicalTopForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002481
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002482 estimateFragmentRangeForBoxChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002483
hyatt@apple.comccad3742015-02-04 21:39:00 +00002484 childBox.markForPaginationRelayoutIfNeeded();
2485 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002486
zalan@apple.com4de96c52017-11-07 04:09:59 +00002487 auto* layoutState = view().frameView().layoutContext().layoutState();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002488 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002489 if (isPaginated) {
2490 // If we are unsplittable and don't fit, then we need to move down.
2491 // We include our margins as part of the unsplittable area.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002492 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, childLogicalTop - logicalTop, marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002493
2494 // See if we have a pagination strut that is making us move down further.
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002495 // Note that an unsplittable child can't also have a pagination strut, so this
2496 // is exclusive with the case above.
cdumez@apple.com5f02e632022-01-16 01:33:25 +00002497 auto* childBlock = dynamicDowncast<RenderBlock>(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002498 if (childBlock && childBlock->paginationStrut()) {
2499 newLogicalTop += childBlock->paginationStrut();
2500 childBlock->setPaginationStrut(0);
2501 }
2502
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002503 if (newLogicalTop != logicalTop) {
2504 floatingObject.setPaginationStrut(newLogicalTop - logicalTop);
2505 computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002506 if (childBlock)
2507 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002508 childBox.layoutIfNeeded();
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002509 logicalTop = newLogicalTop;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002510 }
2511
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002512 if (updateFragmentRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002513 childBox.setNeedsLayout(MarkOnlyThis);
2514 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002515 }
2516 }
2517
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002518 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + (logicalTopForChild(childBox) - logicalTop) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002519
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002520 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002521
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002522 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002523 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002524 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002525 if (childBox.checkForRepaintDuringLayout())
2526 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002527 }
2528 return true;
2529}
2530
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002531void RenderBlockFlow::clearFloats(UsedClear usedClear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002532{
2533 positionNewFloats();
2534 // set y position
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00002535 LayoutUnit newY;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002536 switch (usedClear) {
2537 case UsedClear::Left:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002538 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2539 break;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002540 case UsedClear::Right:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002541 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2542 break;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002543 case UsedClear::Both:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002544 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002545 break;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002546 case UsedClear::None:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002547 break;
2548 }
zalan@apple.com681bd252020-10-08 19:29:23 +00002549 // FIXME: The float search tree has floored float box position (see FloatingObjects::intervalForFloatingObject).
2550 newY = newY.floor();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002551 if (height() < newY)
2552 setLogicalHeight(newY);
2553}
2554
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002555LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002556{
2557 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002558 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002559
2560 return fixedOffset;
2561}
2562
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002563LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002564{
2565 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002566 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002567
2568 return fixedOffset;
2569}
2570
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002571LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002572{
2573 if (!m_floatingObjects)
2574 return logicalHeight;
2575
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002576 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2577}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002578
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002579LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2580{
2581 if (!m_floatingObjects)
2582 return logicalHeight;
2583
2584 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002585}
2586
2587LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2588{
2589 if (!m_floatingObjects)
2590 return 0;
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00002591 LayoutUnit lowestFloatBottom;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002592 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2593 auto end = floatingObjectSet.end();
2594 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002595 const auto& floatingObject = *it->get();
2596 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002597 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002598 }
2599 return lowestFloatBottom;
2600}
2601
hyatt@apple.com87515262014-09-04 21:20:12 +00002602LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2603{
2604 if (!m_floatingObjects)
2605 return 0;
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00002606 LayoutUnit lowestFloatBottom;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002607 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2608 auto end = floatingObjectSet.end();
2609 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002610 const auto& floatingObject = *it->get();
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00002611 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == PseudoId::FirstLetter && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002612 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002613 }
2614 return lowestFloatBottom;
2615}
2616
weinig@apple.com12840dc2013-10-22 23:59:08 +00002617LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002618{
2619 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002620 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002621 return 0;
2622
weinig@apple.com12840dc2013-10-22 23:59:08 +00002623 LayoutUnit childLogicalTop = child.logicalTop();
2624 LayoutUnit childLogicalLeft = child.logicalLeft();
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00002625 LayoutUnit lowestFloatLogicalBottom;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002626
2627 // Floats that will remain the child's responsibility to paint should factor into its
2628 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002629 auto childEnd = child.m_floatingObjects->set().end();
2630 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002631 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002632 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002633 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002634 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002635
2636 if (logicalBottom > logicalHeight()) {
2637 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002638 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002639 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2640 bool shouldPaint = false;
2641
2642 // The nearest enclosing layer always paints the float (so that zindex and stacking
2643 // behaves properly). We always want to propagate the desire to paint the float as
2644 // far out as we can, to the outermost block that overlaps the float, stopping only
2645 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002646 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002647 floatingObject.setPaintsFloat(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002648 shouldPaint = true;
2649 }
2650 // We create the floating object list lazily.
2651 if (!m_floatingObjects)
2652 createFloatingObjects();
2653
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002654 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002655 }
2656 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002657 const auto& renderer = floatingObject.renderer();
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002658 if (makeChildPaintOtherFloats && !floatingObject.paintsFloat() && !renderer.hasSelfPaintingLayer()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002659 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002660 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2661 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2662 // layer.
2663 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2664 // it should paint.
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002665 floatingObject.setPaintsFloat(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002666 }
2667
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002668 // 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 +00002669 if (floatingObject.isDescendant())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002670 child.addOverflowFromChild(&renderer, floatingObject.locationOffsetOfBorderBox());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002671 }
2672 }
2673 return lowestFloatLogicalBottom;
2674}
2675
weinig@apple.com12840dc2013-10-22 23:59:08 +00002676bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002677{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002678 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002679 return false;
2680
2681 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
commit-queue@webkit.orgc27f5ca2018-11-26 19:29:23 +00002682 const auto it = floatingObjectSet.find<FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002683 if (it == floatingObjectSet.end())
2684 return false;
2685
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002686 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002687}
2688
hyatt@apple.com21c60802015-04-01 18:10:32 +00002689void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002690{
2691 ASSERT(!avoidsFloats());
2692
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002693 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2694 if (createsNewFormattingContext())
2695 return;
2696
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002697 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2698 if (!prev->m_floatingObjects)
2699 return;
2700
2701 logicalLeftOffset += marginLogicalLeft();
2702
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002703 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2704 auto prevEnd = prevSet.end();
2705 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002706 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002707 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
commit-queue@webkit.orgc27f5ca2018-11-26 19:29:23 +00002708 if (!m_floatingObjects || !m_floatingObjects->set().contains(&floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002709 // We create the floating object list lazily.
2710 if (!m_floatingObjects)
2711 createFloatingObjects();
2712
2713 // Applying the child's margin makes no sense in the case where the child was passed in.
2714 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2715 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2716 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2717 // will get applied twice.
2718 LayoutSize offset = isHorizontalWritingMode()
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00002719 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : 0_lu), logicalTopOffset)
2720 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : 0_lu));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002721
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002722 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002723 }
2724 }
2725 }
2726}
2727
2728void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2729{
2730 if (!everHadLayout() && !containsFloats())
2731 return;
2732
2733 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2734 setChildNeedsLayout(markParents);
2735
2736 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002737 removeFloatingObject(*floatToRemove);
hyatt@apple.com11a5e5c2016-05-19 21:51:31 +00002738 else if (childrenInline())
hyatt@apple.com00e93142016-05-18 18:59:40 +00002739 return;
2740
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002741 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002742 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2743 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2744 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002745 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002746 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2747 block.setChildNeedsLayout(markParents);
2748 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002749 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002750 auto& blockFlow = downcast<RenderBlockFlow>(block);
commit-queue@webkit.orgf3910b42021-12-10 19:37:38 +00002751 if ((floatToRemove ? blockFlow.subtreeContainsFloat(*floatToRemove) : blockFlow.subtreeContainsFloats()) || blockFlow.shrinkToAvoidFloats())
akling@apple.com525dae62014-01-03 20:22:09 +00002752 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002753 }
2754}
2755
2756void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2757{
2758 if (!m_floatingObjects)
2759 return;
2760
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002761 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2762 auto end = floatingObjectSet.end();
2763
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002764 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002765 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002766 continue;
2767
cdumez@apple.come9437792014-10-08 23:33:43 +00002768 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002769 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2770 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002771 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002772 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002773 if (nextBlock.containsFloat(floatingBox))
2774 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002775 }
2776 }
2777}
2778
zalan@apple.com6816b132015-10-17 19:14:53 +00002779LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002780{
akling@apple.com827be9c2013-10-29 02:58:43 +00002781 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002782 return point;
2783
2784 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2785 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2786 // case.
2787 if (isHorizontalWritingMode())
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002788 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * child.locationOffsetOfBorderBox().height());
2789 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * child.locationOffsetOfBorderBox().width(), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002790}
2791
weinig@apple.com12840dc2013-10-22 23:59:08 +00002792LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002793{
2794 // There is no need to compute clearance if we have no floats.
2795 if (!containsFloats())
2796 return 0;
2797
2798 // At least one float is present. We need to perform the clearance computation.
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002799 UsedClear usedClear = RenderStyle::usedClear(child);
2800 bool clearSet = usedClear != UsedClear::None;
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00002801 LayoutUnit logicalBottom;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002802 switch (usedClear) {
2803 case UsedClear::None:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002804 break;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002805 case UsedClear::Left:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002806 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2807 break;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002808 case UsedClear::Right:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002809 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2810 break;
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00002811 case UsedClear::Both:
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002812 logicalBottom = lowestFloatLogicalBottom();
2813 break;
2814 }
2815
2816 // 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).
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00002817 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : 0_lu;
weinig@apple.com12840dc2013-10-22 23:59:08 +00002818 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002819 LayoutUnit newLogicalTop = logicalTop;
2820 while (true) {
zalan@apple.com64761fe2016-03-02 21:42:22 +00002821 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002822 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2823 return newLogicalTop - logicalTop;
2824
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002825 RenderFragmentContainer* fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2826 LayoutRect borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002827 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2828
2829 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002830 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2831 LayoutUnit childOldMarginLeft = child.marginLeft();
2832 LayoutUnit childOldMarginRight = child.marginRight();
2833 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002834
weinig@apple.com12840dc2013-10-22 23:59:08 +00002835 child.setLogicalTop(newLogicalTop);
2836 child.updateLogicalWidth();
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00002837 fragment = fragmentAtBlockOffset(logicalTopForChild(child));
2838 borderBox = child.borderBoxRectInFragment(fragment, DoNotCacheRenderBoxFragmentInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002839 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2840
weinig@apple.com12840dc2013-10-22 23:59:08 +00002841 child.setLogicalTop(childOldLogicalTop);
2842 child.setLogicalWidth(childOldLogicalWidth);
2843 child.setMarginLeft(childOldMarginLeft);
2844 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002845
zalan@apple.com05c9d8e2022-05-24 18:48:31 +00002846 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002847 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2848 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2849 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2850 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002851 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002852 return newLogicalTop - logicalTop;
2853 }
2854
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002855 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002856 ASSERT(newLogicalTop >= logicalTop);
2857 if (newLogicalTop < logicalTop)
2858 break;
2859 }
2860 ASSERT_NOT_REACHED();
2861 }
2862 return result;
2863}
2864
2865bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2866{
2867 if (!m_floatingObjects)
2868 return false;
2869
2870 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002871 if (is<RenderView>(*this))
2872 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002873
2874 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2875 auto begin = floatingObjectSet.begin();
2876 for (auto it = floatingObjectSet.end(); it != begin;) {
2877 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002878 const auto& floatingObject = *it->get();
2879 auto& renderer = floatingObject.renderer();
simon.fraser@apple.combc9d13c2021-01-27 04:56:57 +00002880 if (floatingObject.shouldPaint()) {
hyatt@apple.comb618b2a2017-03-17 18:54:47 +00002881 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + floatingObject.translationOffsetToAncestor());
zalan@apple.com6816b132015-10-17 19:14:53 +00002882 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002883 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2884 return true;
2885 }
2886 }
2887 }
2888
2889 return false;
2890}
2891
weinig@apple.com611b9292013-10-20 22:57:54 +00002892bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2893{
2894 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002895
antti@apple.com04bca452019-12-09 15:28:48 +00002896#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00002897 if (modernLineLayout())
2898 return modernLineLayout()->hitTest(request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com04bca452019-12-09 15:28:48 +00002899#endif
antti@apple.com940f5872013-10-24 20:31:11 +00002900
antti@apple.com443deba2021-06-01 13:58:23 +00002901 return legacyLineLayout() && legacyLineLayout()->lineBoxes().hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com50b36fde2019-08-11 11:02:01 +00002902}
2903
2904void RenderBlockFlow::addOverflowFromInlineChildren()
2905{
antti@apple.com4789a082019-12-08 15:30:50 +00002906#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00002907 if (modernLineLayout()) {
2908 modernLineLayout()->collectOverflow();
antti@apple.com4789a082019-12-08 15:30:50 +00002909 return;
2910 }
2911#endif
2912
antti@apple.com443deba2021-06-01 13:58:23 +00002913 if (legacyLineLayout())
2914 legacyLineLayout()->addOverflowFromInlineChildren();
weinig@apple.com611b9292013-10-20 22:57:54 +00002915}
2916
antti@apple.com903292a2021-06-02 16:20:15 +00002917void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, LegacyRootInlineBox* highest)
weinig@apple.com611b9292013-10-20 22:57:54 +00002918{
2919 if (logicalTop >= logicalBottom)
2920 return;
2921
antti@apple.comd685c412019-12-07 13:56:51 +00002922 // Floats currently affect the choice of layout path.
antti@apple.comd685c412019-12-07 13:56:51 +00002923#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00002924 if (modernLineLayout()) {
antti@apple.comd685c412019-12-07 13:56:51 +00002925 invalidateLineLayoutPath();
2926 return;
2927 }
2928#endif
2929
antti@apple.com903292a2021-06-02 16:20:15 +00002930 LegacyRootInlineBox* lowestDirtyLine = lastRootBox();
2931 LegacyRootInlineBox* afterLowest = lowestDirtyLine;
antti@apple.com657a14e2020-10-29 15:51:07 +00002932 while (lowestDirtyLine && lowestDirtyLine->lineBoxBottom() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002933 afterLowest = lowestDirtyLine;
2934 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2935 }
2936
antti@apple.com657a14e2020-10-29 15:51:07 +00002937 while (afterLowest && afterLowest != highest && (afterLowest->lineBoxBottom() >= logicalTop || afterLowest->lineBoxBottom() < 0)) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002938 afterLowest->markDirty();
2939 afterLowest = afterLowest->prevRootBox();
2940 }
2941}
2942
darin@apple.coma4ddc782021-05-30 16:11:40 +00002943std::optional<LayoutUnit> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00002944{
jfernandez@igalia.comf119ec12018-11-23 11:04:23 +00002945 if (isWritingModeRoot() && !isRubyRun() && !isGridItem())
darin@apple.com7c840b62021-05-28 01:26:23 +00002946 return std::nullopt;
weinig@apple.com611b9292013-10-20 22:57:54 +00002947
simon.fraser@apple.come8ee49b2022-05-06 17:10:31 +00002948 if (shouldApplyLayoutContainment())
darin@apple.com7c840b62021-05-28 01:26:23 +00002949 return std::nullopt;
commit-queue@webkit.org71fc28e2021-04-19 06:13:38 +00002950
weinig@apple.com611b9292013-10-20 22:57:54 +00002951 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00002952 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00002953
antti@apple.com940f5872013-10-24 20:31:11 +00002954 if (!hasLines())
darin@apple.com7c840b62021-05-28 01:26:23 +00002955 return std::nullopt;
weinig@apple.com611b9292013-10-20 22:57:54 +00002956
antti@apple.comd685c412019-12-07 13:56:51 +00002957#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00002958 if (modernLineLayout())
zalan@apple.com74741182022-02-16 17:29:44 +00002959 return LayoutUnit { floorToInt(modernLineLayout()->firstLinePhysicalBaseline()) };
antti@apple.comd685c412019-12-07 13:56:51 +00002960#endif
2961
akling@apple.comee3c8df2013-11-06 08:09:44 +00002962 ASSERT(firstRootBox());
jfernandez@igalia.combe5a04c2018-11-22 08:45:48 +00002963 if (style().isFlippedLinesWritingMode())
mmaxfield@apple.com881a9362022-02-02 05:12:47 +00002964 return LayoutUnit { firstRootBox()->logicalTop() + firstLineStyle().metricsOfPrimaryFont().descent(firstRootBox()->baselineType()) };
2965 return LayoutUnit { firstRootBox()->logicalTop() + firstLineStyle().metricsOfPrimaryFont().ascent(firstRootBox()->baselineType()) };
weinig@apple.com611b9292013-10-20 22:57:54 +00002966}
2967
darin@apple.coma4ddc782021-05-30 16:11:40 +00002968std::optional<LayoutUnit> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00002969{
2970 if (isWritingModeRoot() && !isRubyRun())
darin@apple.com7c840b62021-05-28 01:26:23 +00002971 return std::nullopt;
weinig@apple.com611b9292013-10-20 22:57:54 +00002972
simon.fraser@apple.come8ee49b2022-05-06 17:10:31 +00002973 if (shouldApplyLayoutContainment())
commit-queue@webkit.org71fc28e2021-04-19 06:13:38 +00002974 return RenderBlock::inlineBlockBaseline(lineDirection);
2975
zalan@apple.com7b0eeb42021-01-09 13:14:18 +00002976 if (style().display() == DisplayType::InlineBlock) {
2977 // The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or if its 'overflow'
2978 // property has a computed value other than 'visible'. see https://www.w3.org/TR/CSS22/visudet.html
2979 auto shouldSynthesizeBaseline = !style().isOverflowVisible() && !is<HTMLFormControlElement>(element());
2980 if (shouldSynthesizeBaseline)
darin@apple.com7c840b62021-05-28 01:26:23 +00002981 return std::nullopt;
zalan@apple.com7b0eeb42021-01-09 13:14:18 +00002982 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00002983 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
commit-queue@webkit.org7b557b42021-04-06 08:37:33 +00002984 float boxHeight = synthesizedBaselineFromBorderBox(*this, lineDirection) + (lineDirection == HorizontalLine ? m_marginBox.bottom() : m_marginBox.left());
antti@apple.com55d5afa2020-09-25 13:16:23 +00002985 float lastBaseline = 0;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002986 if (!childrenInline()) {
commit-queue@webkit.orge93d4f02021-04-02 09:07:41 +00002987 auto inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002988 if (!inlineBlockBaseline)
2989 return inlineBlockBaseline;
2990 lastBaseline = inlineBlockBaseline.value();
2991 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00002992 if (!hasLines()) {
2993 if (!hasLineIfEmpty())
darin@apple.com7c840b62021-05-28 01:26:23 +00002994 return std::nullopt;
mmaxfield@apple.com881a9362022-02-02 05:12:47 +00002995 const auto& fontMetrics = firstLineStyle().metricsOfPrimaryFont();
commit-queue@webkit.orge93d4f02021-04-02 09:07:41 +00002996 return LayoutUnit { LayoutUnit(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00002997 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
commit-queue@webkit.orge93d4f02021-04-02 09:07:41 +00002998 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight())).toInt() };
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00002999 }
3000
antti@apple.com443deba2021-06-01 13:58:23 +00003001 if (legacyLineLayout()) {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003002 bool isFirstLine = lastRootBox() == firstRootBox();
3003 const auto& style = isFirstLine ? firstLineStyle() : this->style();
antti@apple.comb1ddc662021-06-03 13:39:56 +00003004 // LegacyInlineFlowBox::placeBoxesInBlockDirection will flip lines in case of verticalLR mode, so we can assume verticalRL for now.
mmaxfield@apple.com881a9362022-02-02 05:12:47 +00003005 lastBaseline = style.metricsOfPrimaryFont().ascent(lastRootBox()->baselineType())
jfernandez@igalia.com7e696b92018-02-01 01:56:52 +00003006 + (style.isFlippedLinesWritingMode() ? logicalHeight() - lastRootBox()->logicalBottom() : lastRootBox()->logicalTop());
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003007 }
antti@apple.com55d5afa2020-09-25 13:16:23 +00003008#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00003009 else if (modernLineLayout())
zalan@apple.com74741182022-02-16 17:29:44 +00003010 lastBaseline = floorToInt(modernLineLayout()->lastLineLogicalBaseline());
antti@apple.com55d5afa2020-09-25 13:16:23 +00003011#endif
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003012 }
3013 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3014 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3015 // enough with the spec to not cause tons of breakages).
commit-queue@webkit.orge93d4f02021-04-02 09:07:41 +00003016 return LayoutUnit { style().overflowY() == Overflow::Visible ? lastBaseline : std::min(boxHeight, lastBaseline) };
weinig@apple.com611b9292013-10-20 22:57:54 +00003017}
3018
zalan@apple.comc6d5b442022-03-15 21:17:33 +00003019LayoutUnit RenderBlockFlow::adjustEnclosingTopForPrecedingBlock(LayoutUnit top) const
antti@apple.com9081c9f2021-09-16 19:19:39 +00003020{
3021 if (selectionState() != RenderObject::HighlightState::Inside && selectionState() != RenderObject::HighlightState::End)
3022 return top;
3023
3024 if (isSelectionRoot())
3025 return top;
3026
3027 LayoutSize offsetToBlockBefore;
3028
3029 auto blockBeforeWithinSelectionRoot = [&]() -> const RenderBlockFlow* {
3030 const RenderElement* object = this;
3031 const RenderObject* sibling = nullptr;
3032 do {
3033 sibling = object->previousSibling();
3034 while (sibling && (!is<RenderBlock>(*sibling) || downcast<RenderBlock>(*sibling).isSelectionRoot()))
3035 sibling = sibling->previousSibling();
3036
3037 offsetToBlockBefore -= LayoutSize(downcast<RenderBlock>(*object).logicalLeft(), downcast<RenderBlock>(*object).logicalTop());
3038 object = object->parent();
3039 } while (!sibling && is<RenderBlock>(object) && !downcast<RenderBlock>(*object).isSelectionRoot());
3040
3041 if (!sibling)
3042 return nullptr;
3043
3044 auto* beforeBlock = downcast<RenderBlock>(sibling);
3045
3046 offsetToBlockBefore += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3047
3048 auto* child = beforeBlock->lastChild();
3049 while (is<RenderBlock>(child)) {
3050 beforeBlock = downcast<RenderBlock>(child);
3051 offsetToBlockBefore += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3052 child = beforeBlock->lastChild();
3053 }
3054 return is<RenderBlockFlow>(beforeBlock) ? downcast<RenderBlockFlow>(beforeBlock) : nullptr;
3055 };
3056
3057 auto* blockBefore = blockBeforeWithinSelectionRoot();
3058 if (!blockBefore)
3059 return top;
3060
3061 // Do not adjust blocks sharing the same line.
3062 if (!offsetToBlockBefore.height())
3063 return top;
3064
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003065 if (auto lastLineBox = InlineIterator::lastLineBoxFor(*blockBefore)) {
3066 auto lastLineSelectionState = LineSelection::selectionState(*lastLineBox);
antti@apple.com9081c9f2021-09-16 19:19:39 +00003067 if (lastLineSelectionState != RenderObject::HighlightState::Inside && lastLineSelectionState != RenderObject::HighlightState::Start)
3068 return top;
3069
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003070 auto lastLineSelectionBottom = LineSelection::logicalBottom(*lastLineBox) + offsetToBlockBefore.height();
zalan@apple.comc7af2352022-03-20 00:45:31 +00003071 top = std::max(top, LayoutUnit { lastLineSelectionBottom });
antti@apple.com9081c9f2021-09-16 19:19:39 +00003072 }
3073 return top;
3074}
3075
weinig@apple.com12840dc2013-10-22 23:59:08 +00003076GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003077 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3078{
megan_gardner@apple.comc66f2b82020-02-10 19:32:19 +00003079 bool containsStart = selectionState() == HighlightState::Start || selectionState() == HighlightState::Both;
weinig@apple.com611b9292013-10-20 22:57:54 +00003080
antti@apple.com0e632aa2013-10-22 21:03:38 +00003081 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003082 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003083 // 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 +00003084 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3085 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3086 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3087 }
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003088 return { };
weinig@apple.com611b9292013-10-20 22:57:54 +00003089 }
3090
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003091 auto hasSelectedChildren = [&](const InlineIterator::LineBoxIterator& lineBox) {
3092 return LineSelection::selectionState(*lineBox) != RenderObject::HighlightState::None;
antti@apple.com40042cf2021-01-10 12:04:02 +00003093 };
3094
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003095 auto lineSelectionGap = [&](const InlineIterator::LineBoxIterator& lineBox, LayoutUnit selTop, LayoutUnit selHeight) -> GapRects {
3096 auto lineState = LineSelection::selectionState(*lineBox);
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003097
3098 bool leftGap, rightGap;
3099 getSelectionGapInfo(lineState, leftGap, rightGap);
3100
3101 GapRects result;
3102
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003103 auto firstSelectedBox = [&]() -> InlineIterator::LeafBoxIterator {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003104 for (auto box = lineBox->firstLeafBox(); box; box.traverseNextOnLine()) {
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003105 if (box->selectionState() != RenderObject::HighlightState::None)
3106 return box;
3107 }
3108 return { };
3109 }();
3110
3111 auto lastSelectedBox = [&]() -> InlineIterator::LeafBoxIterator {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003112 for (auto box = lineBox->lastLeafBox(); box; box.traversePreviousOnLine()) {
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003113 if (box->selectionState() != RenderObject::HighlightState::None)
3114 return box;
3115 }
3116 return { };
3117 }();
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003118
3119 if (leftGap) {
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003120 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, firstSelectedBox->renderer().parent(), LayoutUnit(firstSelectedBox->logicalLeft()),
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003121 selTop, selHeight, cache, paintInfo));
3122 }
3123 if (rightGap) {
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003124 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastSelectedBox->renderer().parent(), LayoutUnit(lastSelectedBox->logicalRight()),
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003125 selTop, selHeight, cache, paintInfo));
3126 }
3127
3128 // When dealing with bidi text, a non-contiguous selection region is possible.
3129 // e.g. The logical text aaaAAAbbb (capitals denote RTL text and non-capitals LTR) is layed out
3130 // visually as 3 text runs |aaa|bbb|AAA| if we select 4 characters from the start of the text the
3131 // selection will look like (underline denotes selection):
3132 // |aaa|bbb|AAA|
3133 // ___ _
3134 // We can see that the |bbb| run is not part of the selection while the runs around it are.
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003135 if (firstSelectedBox && firstSelectedBox != lastSelectedBox) {
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003136 // Now fill in any gaps on the line that occurred between two selected elements.
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003137 LayoutUnit lastLogicalLeft { firstSelectedBox->logicalRight() };
3138 bool isPreviousBoxSelected = firstSelectedBox->selectionState() != RenderObject::HighlightState::None;
3139 for (auto box = firstSelectedBox; box; box.traverseNextOnLine()) {
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003140 if (box->selectionState() != RenderObject::HighlightState::None) {
3141 LayoutRect logicalRect { lastLogicalLeft, selTop, LayoutUnit(box->logicalLeft() - lastLogicalLeft), selHeight };
3142 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : LayoutSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
3143 LayoutRect gapRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3144 if (isPreviousBoxSelected && gapRect.width() > 0 && gapRect.height() > 0) {
3145 if (paintInfo && box->renderer().parent()->style().visibility() == Visibility::Visible)
3146 paintInfo->context().fillRect(gapRect, box->renderer().parent()->selectionBackgroundColor());
3147 // VisibleSelection may be non-contiguous, see comment above.
3148 result.uniteCenter(gapRect);
3149 }
3150 lastLogicalLeft = box->logicalRight();
3151 }
zalan@apple.com8bcfa322022-03-16 14:41:56 +00003152 if (box == lastSelectedBox)
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003153 break;
3154 isPreviousBoxSelected = box->selectionState() != RenderObject::HighlightState::None;
3155 }
3156 }
3157
3158 return result;
3159 };
3160
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003161 InlineIterator::LineBoxIterator lastSelectedLineBox;
3162 auto lineBox = InlineIterator::firstLineBoxFor(*this);
3163 for (; lineBox && !hasSelectedChildren(lineBox); lineBox.traverseNext()) { }
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003164
3165 GapRects result;
weinig@apple.com611b9292013-10-20 22:57:54 +00003166
3167 // Now paint the gaps for the lines.
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003168 for (; lineBox && hasSelectedChildren(lineBox); lineBox.traverseNext()) {
3169 auto selectionTop = LayoutUnit { LineSelection::logicalTopAdjustedForPrecedingBlock(*lineBox) };
3170 auto selectionHeight = LayoutUnit { std::max(0.f, LineSelection::logicalBottom(*lineBox) - selectionTop) };
weinig@apple.com611b9292013-10-20 22:57:54 +00003171
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003172 if (!containsStart && !lastSelectedLineBox
3173 && selectionState() != HighlightState::Start
3174 && selectionState() != HighlightState::Both && !isRubyBase())
zalan@apple.com928aaf92022-03-18 02:30:52 +00003175 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selectionTop, cache, paintInfo));
antti@apple.comf8a9ad82021-09-19 16:42:57 +00003176
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003177 LayoutRect logicalRect { LayoutUnit(lineBox->contentLogicalLeft()), selectionTop, LayoutUnit(lineBox->contentLogicalWidth()), selectionTop + selectionHeight };
weinig@apple.com611b9292013-10-20 22:57:54 +00003178 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003179 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003180 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3181 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003182 result.unite(lineSelectionGap(lineBox, selectionTop, selectionHeight));
weinig@apple.com611b9292013-10-20 22:57:54 +00003183
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003184 lastSelectedLineBox = lineBox;
weinig@apple.com611b9292013-10-20 22:57:54 +00003185 }
3186
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003187 if (containsStart && !lastSelectedLineBox) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003188 // VisibleSelection must start just after our last line.
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003189 lastSelectedLineBox = InlineIterator::lastLineBoxFor(*this);
3190 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003191
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003192 if (lastSelectedLineBox && selectionState() != HighlightState::End && selectionState() != HighlightState::Both) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003193 // Update our lastY to be the bottom of the last selected line.
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003194 auto lastLineSelectionBottom = LayoutUnit { LineSelection::logicalBottom(*lastSelectedLineBox) };
zalan@apple.comcebeed72022-03-17 15:24:31 +00003195 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastLineSelectionBottom;
3196 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastLineSelectionBottom, cache);
3197 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastLineSelectionBottom, cache);
weinig@apple.com611b9292013-10-20 22:57:54 +00003198 }
3199 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003200}
3201
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003202bool RenderBlockFlow::needsLayoutAfterFragmentRangeChange() const
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003203{
3204 // A block without floats or that expands to enclose them won't need a relayout
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003205 // after a fragment range change. There is no overflow content needing relayout
3206 // in the fragment chain because the fragment range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003207 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003208 return false;
3209
3210 return true;
3211}
3212
zalan@apple.com624c2642017-10-05 14:04:27 +00003213void RenderBlockFlow::setMultiColumnFlow(RenderMultiColumnFlow& fragmentedFlow)
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003214{
zalan@apple.com624c2642017-10-05 14:04:27 +00003215 ASSERT(!hasRareBlockFlowData() || !rareBlockFlowData()->m_multiColumnFlow);
cdumez@apple.comf440d4c2021-10-13 15:37:52 +00003216 ensureRareBlockFlowData().m_multiColumnFlow = fragmentedFlow;
zalan@apple.com624c2642017-10-05 14:04:27 +00003217}
3218
3219void RenderBlockFlow::clearMultiColumnFlow()
3220{
3221 ASSERT(hasRareBlockFlowData());
3222 ASSERT(rareBlockFlowData()->m_multiColumnFlow);
3223 rareBlockFlowData()->m_multiColumnFlow.clear();
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003224}
3225
antti@apple.com702ef7d2019-12-06 14:37:43 +00003226int RenderBlockFlow::lineCount() const
weinig@apple.com17140912013-10-19 19:55:40 +00003227{
zalan@apple.com93658f62022-04-10 21:56:21 +00003228 if (!childrenInline()) {
3229 ASSERT_NOT_REACHED();
weinig@apple.com17140912013-10-19 19:55:40 +00003230 return 0;
zalan@apple.com93658f62022-04-10 21:56:21 +00003231 }
antti@apple.com702ef7d2019-12-06 14:37:43 +00003232#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
zalan@apple.com93658f62022-04-10 21:56:21 +00003233 if (modernLineLayout())
3234 return modernLineLayout()->lineCount();
antti@apple.com702ef7d2019-12-06 14:37:43 +00003235#endif
zalan@apple.com93658f62022-04-10 21:56:21 +00003236 if (legacyLineLayout())
3237 return legacyLineLayout()->lineCount();
antti@apple.com702ef7d2019-12-06 14:37:43 +00003238
zalan@apple.com93658f62022-04-10 21:56:21 +00003239 return 0;
weinig@apple.com17140912013-10-19 19:55:40 +00003240}
3241
weinig@apple.com3f23b382013-10-19 20:26:58 +00003242bool RenderBlockFlow::containsNonZeroBidiLevel() const
3243{
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003244 for (auto lineBox = InlineIterator::firstLineBoxFor(*this); lineBox; lineBox.traverseNext()) {
3245 for (auto box = lineBox->firstLeafBox(); box; box = box.traverseNextOnLine()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003246 if (box->bidiLevel())
3247 return true;
3248 }
3249 }
3250 return false;
3251}
3252
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003253static Position positionForRun(const RenderBlockFlow& flow, InlineIterator::BoxIterator box, bool start)
weinig@apple.com611b9292013-10-20 22:57:54 +00003254{
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003255 if (!box)
weinig@apple.com611b9292013-10-20 22:57:54 +00003256 return Position();
3257
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003258 if (!box->renderer().nonPseudoNode())
antti@apple.com4c0c3972020-10-29 14:21:34 +00003259 return makeDeprecatedLegacyPosition(flow.nonPseudoElement(), start ? flow.caretMinOffset() : flow.caretMaxOffset());
weinig@apple.com611b9292013-10-20 22:57:54 +00003260
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003261 if (!is<InlineIterator::TextBoxIterator>(box))
3262 return makeDeprecatedLegacyPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
weinig@apple.com611b9292013-10-20 22:57:54 +00003263
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003264 auto& textBox = downcast<InlineIterator::TextBoxIterator>(box);
3265 return makeDeprecatedLegacyPosition(textBox->renderer().nonPseudoNode(), start ? textBox->start() : textBox->end());
weinig@apple.com611b9292013-10-20 22:57:54 +00003266}
3267
enrica@apple.com0db51a62016-04-27 23:53:08 +00003268RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
3269{
3270 // A light, non-recursive version of RenderBlock::positionForCoordinates that looks at
3271 // whether a point lies within the gaps between its root line boxes, to be called against
3272 // a node returned from elementAtPoint. We make the assumption that either the node or one
3273 // of its immediate children contains the root line boxes in question.
3274 // See <rdar://problem/6824650> for context.
3275
3276 RenderBlock* block = this;
3277
3278 FloatPoint localPoint = block->absoluteToLocal(point);
3279
3280 if (!block->childrenInline()) {
3281 // Look among our immediate children for an alternate box that contains the point.
3282 for (RenderBox* child = block->firstChildBox(); child; child = child->nextSiblingBox()) {
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00003283 if (!child->height() || child->style().visibility() != WebCore::Visibility::Visible || child->isFloatingOrOutOfFlowPositioned())
enrica@apple.com0db51a62016-04-27 23:53:08 +00003284 continue;
3285 float top = child->y();
3286
3287 RenderBox* nextChild = child->nextSiblingBox();
3288 while (nextChild && nextChild->isFloatingOrOutOfFlowPositioned())
3289 nextChild = nextChild->nextSiblingBox();
3290 if (!nextChild) {
3291 if (localPoint.y() >= top) {
3292 block = downcast<RenderBlock>(child);
3293 break;
3294 }
3295 continue;
3296 }
3297
3298 float bottom = nextChild->y();
3299
3300 if (localPoint.y() >= top && localPoint.y() < bottom && is<RenderBlock>(*child)) {
3301 block = downcast<RenderBlock>(child);
3302 break;
3303 }
3304 }
3305
3306 if (!block->childrenInline())
3307 return nullptr;
3308
3309 localPoint = block->absoluteToLocal(point);
3310 }
3311
3312 RenderBlockFlow& blockFlow = downcast<RenderBlockFlow>(*block);
3313
3314 // Only check the gaps between the root line boxes. We deliberately ignore overflow because
3315 // experience has shown that hit tests on an exploded text node can fail when within the
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003316 // overflow fragment.
zalan@apple.comfa6423d2022-03-12 14:30:45 +00003317 auto previousRootInlineBoxBottom = std::optional<float> { };
3318 for (auto box = InlineIterator::firstRootInlineBoxFor(blockFlow); box; box.traverseNextInlineBox()) {
3319 if (previousRootInlineBoxBottom) {
3320 if (localPoint.y() < *previousRootInlineBoxBottom)
3321 return nullptr;
3322
3323 if (localPoint.y() > *previousRootInlineBoxBottom && localPoint.y() < box->logicalTop()) {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003324 auto closestBox = closestBoxForHorizontalPosition(*box->lineBox(), localPoint.x());
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003325 if (closestBox && is<RenderText>(closestBox->renderer()))
3326 return const_cast<RenderText*>(&downcast<RenderText>(closestBox->renderer()));
zalan@apple.comfa6423d2022-03-12 14:30:45 +00003327 }
enrica@apple.com0db51a62016-04-27 23:53:08 +00003328 }
zalan@apple.comfa6423d2022-03-12 14:30:45 +00003329 previousRootInlineBoxBottom = box->logicalBottom();
enrica@apple.com0db51a62016-04-27 23:53:08 +00003330 }
3331 return nullptr;
3332}
3333
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003334VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderFragmentContainer* fragment)
weinig@apple.com611b9292013-10-20 22:57:54 +00003335{
3336 ASSERT(childrenInline());
3337
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003338 auto firstLineBox = InlineIterator::firstLineBoxFor(*this);
antti@apple.com940f5872013-10-24 20:31:11 +00003339
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003340 if (!firstLineBox)
darin@apple.comc8d8b552020-09-03 21:38:50 +00003341 return createVisiblePosition(0, Affinity::Downstream);
weinig@apple.com611b9292013-10-20 22:57:54 +00003342
akling@apple.com827be9c2013-10-29 02:58:43 +00003343 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3344 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003345
3346 // look for the closest line box in the root box which is at the passed-in y coordinate
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003347 InlineIterator::LeafBoxIterator closestBox;
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003348 InlineIterator::LineBoxIterator firstLineBoxWithChildren;
3349 InlineIterator::LineBoxIterator lastLineBoxWithChildren;
3350 for (auto lineBox = firstLineBox; lineBox; lineBox.traverseNext()) {
3351 if (fragment && lineBox->containingFragment() != fragment)
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003352 continue;
3353
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003354 if (!lineBox->firstLeafBox())
weinig@apple.com611b9292013-10-20 22:57:54 +00003355 continue;
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003356 if (!firstLineBoxWithChildren)
3357 firstLineBoxWithChildren = lineBox;
weinig@apple.com611b9292013-10-20 22:57:54 +00003358
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003359 if (!linesAreFlipped && lineBox->isFirstAfterPageBreak()
3360 && (pointInLogicalContents.y() < lineBox->top() || (blocksAreFlipped && pointInLogicalContents.y() == lineBox->top())))
weinig@apple.com611b9292013-10-20 22:57:54 +00003361 break;
3362
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003363 lastLineBoxWithChildren = lineBox;
weinig@apple.com611b9292013-10-20 22:57:54 +00003364
3365 // check if this root line box is located at this y coordinate
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003366 auto selectionBottom = LineSelection::logicalBottom(*lineBox);
zalan@apple.comcebeed72022-03-17 15:24:31 +00003367 if (pointInLogicalContents.y() < selectionBottom || (blocksAreFlipped && pointInLogicalContents.y() == selectionBottom)) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003368 if (linesAreFlipped) {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003369 auto nextLineBoxWithChildren = lineBox->next();
3370 while (nextLineBoxWithChildren && !nextLineBoxWithChildren->firstLeafBox())
3371 nextLineBoxWithChildren.traverseNext();
weinig@apple.com611b9292013-10-20 22:57:54 +00003372
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003373 if (nextLineBoxWithChildren && nextLineBoxWithChildren->isFirstAfterPageBreak()
3374 && (pointInLogicalContents.y() > nextLineBoxWithChildren->top() || (!blocksAreFlipped && pointInLogicalContents.y() == nextLineBoxWithChildren->top())))
weinig@apple.com611b9292013-10-20 22:57:54 +00003375 continue;
3376 }
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003377 closestBox = closestBoxForHorizontalPosition(*lineBox, pointInLogicalContents.x());
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003378 if (closestBox)
weinig@apple.com611b9292013-10-20 22:57:54 +00003379 break;
3380 }
3381 }
3382
3383 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3384
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003385 if (!moveCaretToBoundary && !closestBox && lastLineBoxWithChildren) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003386 // y coordinate is below last root line box, pretend we hit it
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003387 closestBox = closestBoxForHorizontalPosition(*lastLineBoxWithChildren, pointInLogicalContents.x());
weinig@apple.com611b9292013-10-20 22:57:54 +00003388 }
3389
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003390 if (closestBox) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003391 if (moveCaretToBoundary) {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003392 auto firstLineWithChildrenTop = LayoutUnit { std::min(previousLineBoxContentBottomOrBorderAndPadding(*firstLineBoxWithChildren), firstLineBoxWithChildren->contentLogicalTop()) };
antti@apple.com4c0c3972020-10-29 14:21:34 +00003393 if (pointInLogicalContents.y() < firstLineWithChildrenTop
3394 || (blocksAreFlipped && pointInLogicalContents.y() == firstLineWithChildrenTop)) {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003395 auto box = firstLineBoxWithChildren->firstLeafBox();
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003396 if (box->isLineBreak()) {
3397 if (auto next = box->nextOnLineIgnoringLineBreak())
3398 box = next;
weinig@apple.com611b9292013-10-20 22:57:54 +00003399 }
3400 // y coordinate is above first root line box, so return the start of the first
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003401 return positionForRun(*this, box, true);
weinig@apple.com611b9292013-10-20 22:57:54 +00003402 }
3403 }
3404
3405 // pass the box a top position that is inside it
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003406 auto point = LayoutPoint { pointInLogicalContents.x(), contentStartInBlockDirection(*closestBox->lineBox()) };
weinig@apple.com611b9292013-10-20 22:57:54 +00003407 if (!isHorizontalWritingMode())
3408 point = point.transposedPoint();
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003409 if (closestBox->renderer().isReplacedOrInlineBlock())
3410 return positionForPointRespectingEditingBoundaries(*this, const_cast<RenderBox&>(downcast<RenderBox>(closestBox->renderer())), point);
3411 return const_cast<RenderObject&>(closestBox->renderer()).positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003412 }
3413
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003414 if (lastLineBoxWithChildren) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003415 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3416 ASSERT(moveCaretToBoundary);
antti@apple.com36b223a2021-10-15 20:29:15 +00003417 InlineIterator::LineLogicalOrderCache orderCache;
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003418 if (auto logicallyLastBox = InlineIterator::lastLeafOnLineInLogicalOrderWithNode(lastLineBoxWithChildren, orderCache))
zalan@apple.com0c2712d2022-03-18 13:49:15 +00003419 return positionForRun(*this, logicallyLastBox, false);
weinig@apple.com611b9292013-10-20 22:57:54 +00003420 }
3421
3422 // Can't reach this. We have a root line box, but it has no kids.
3423 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3424 // seems to hit this code path.
darin@apple.comc8d8b552020-09-03 21:38:50 +00003425 return createVisiblePosition(0, Affinity::Downstream);
weinig@apple.com611b9292013-10-20 22:57:54 +00003426}
3427
zalan@apple.com0d5951b2017-02-19 16:24:20 +00003428Position RenderBlockFlow::positionForPoint(const LayoutPoint& point)
3429{
antti@apple.com55d5afa2020-09-25 13:16:23 +00003430 return positionForPoint(point, nullptr).deepEquivalent();
zalan@apple.com0d5951b2017-02-19 16:24:20 +00003431}
3432
hyatt@apple.come0d2e0f2017-09-27 16:19:08 +00003433VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderFragmentContainer*)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003434{
antti@apple.come0e8a562017-09-21 18:29:47 +00003435 return RenderBlock::positionForPoint(point, nullptr);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003436}
3437
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003438void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
weinig@apple.com611b9292013-10-20 22:57:54 +00003439{
antti@apple.com940f5872013-10-24 20:31:11 +00003440 ASSERT(childrenInline());
antti@apple.com631a4762022-01-02 18:30:52 +00003441 for (auto box = InlineIterator::firstRootInlineBoxFor(*this); box; box.traverseNextInlineBox()) {
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003442 auto lineBox = box->lineBox();
antti@apple.com631a4762022-01-02 18:30:52 +00003443 // FIXME: This is mixing physical and logical coordinates.
zalan@apple.com6a254052022-03-01 16:19:30 +00003444 auto unflippedVisualRect = box->visualRectIgnoringBlockDirection();
zalan@apple.com1ae704f2022-03-21 00:59:06 +00003445 auto top = std::max(lineBox->contentLogicalTop(), unflippedVisualRect.y());
3446 auto bottom = std::min(lineBox->contentLogicalBottom(), unflippedVisualRect.maxY());
zalan@apple.com6a254052022-03-01 16:19:30 +00003447 auto rect = LayoutRect { LayoutUnit { additionalOffset.x() + unflippedVisualRect.x() }
3448 , additionalOffset.y() + top
3449 , LayoutUnit { unflippedVisualRect.width() }
3450 , bottom - top };
weinig@apple.com611b9292013-10-20 22:57:54 +00003451 if (!rect.isEmpty())
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003452 rects.append(rect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003453 }
3454}
3455
3456void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3457{
3458 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003459
antti@apple.com1880e712019-11-26 20:15:39 +00003460#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00003461 if (modernLineLayout()) {
3462 modernLineLayout()->paint(paintInfo, paintOffset);
antti@apple.com1880e712019-11-26 20:15:39 +00003463 return;
3464 }
3465#endif
3466
antti@apple.com443deba2021-06-01 13:58:23 +00003467 if (legacyLineLayout())
3468 legacyLineLayout()->lineBoxes().paint(this, paintInfo, paintOffset);
weinig@apple.com611b9292013-10-20 22:57:54 +00003469}
3470
zalan@apple.com4a440322017-11-10 00:31:24 +00003471bool RenderBlockFlow::relayoutForPagination()
weinig@apple.com611b9292013-10-20 22:57:54 +00003472{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003473 if (!multiColumnFlow() || !multiColumnFlow()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003474 return false;
3475
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003476 multiColumnFlow()->setNeedsHeightsRecalculation(false);
3477 multiColumnFlow()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003478
3479 bool needsRelayout;
3480 bool neededRelayout = false;
3481 bool firstPass = true;
3482 do {
3483 // Column heights may change here because of balancing. We may have to do multiple layout
3484 // passes, depending on how the contents is fitted to the changed column heights. In most
3485 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3486 // passes than that, though, but the number of retries should not exceed the number of
3487 // columns, unless we have a bug.
3488 needsRelayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003489 for (RenderMultiColumnSet* multicolSet = multiColumnFlow()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003490 if (multicolSet->recalculateColumnHeight(firstPass))
3491 needsRelayout = true;
3492 if (needsRelayout) {
3493 // Once a column set gets a new column height, that column set and all successive column
3494 // sets need to be laid out over again, since their logical top will be affected by
3495 // this, and therefore their column heights may change as well, at least if the multicol
3496 // height is constrained.
3497 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003498 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003499 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003500 if (needsRelayout) {
3501 // Layout again. Column balancing resulted in a new height.
3502 neededRelayout = true;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003503 multiColumnFlow()->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003504 setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003505 layoutBlock(false);
3506 }
3507 firstPass = false;
3508 } while (needsRelayout);
3509
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003510 multiColumnFlow()->setInBalancingPass(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003511
3512 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003513}
3514
antti@apple.com940f5872013-10-24 20:31:11 +00003515bool RenderBlockFlow::hasLines() const
3516{
zalan@apple.com93658f62022-04-10 21:56:21 +00003517 return childrenInline() ? lineCount() : false;
antti@apple.com940f5872013-10-24 20:31:11 +00003518}
3519
antti@apple.com9e891c82014-05-22 06:12:34 +00003520void RenderBlockFlow::invalidateLineLayoutPath()
3521{
akling@apple.coma12fee22015-02-01 02:58:13 +00003522 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003523 case UndeterminedPath:
zalan@apple.com515e3702021-10-11 15:55:01 +00003524 case ForcedLegacyPath:
antti@apple.com9e891c82014-05-22 06:12:34 +00003525 return;
zalan@apple.com515e3702021-10-11 15:55:01 +00003526 case LegacyPath:
akling@apple.coma12fee22015-02-01 02:58:13 +00003527 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003528 return;
antti@apple.com467972e2021-02-22 15:30:26 +00003529 case ModernPath: {
3530 // FIXME: Implement partial invalidation.
dpino@igalia.com3b24f6502021-02-23 15:05:07 +00003531 auto path = UndeterminedPath;
3532#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
3533 if (modernLineLayout() && modernLineLayout()->shouldSwitchToLegacyOnInvalidation())
zalan@apple.com515e3702021-10-11 15:55:01 +00003534 path = ForcedLegacyPath;
dpino@igalia.com3b24f6502021-02-23 15:05:07 +00003535#endif
zalan@apple.com713445c2021-11-18 21:14:07 +00003536#if ENABLE_MODERN_PREFERRED_WIDTH_COMPUTATION
3537 for (auto walker = InlineWalker(*this); !walker.atEnd(); walker.advance())
3538 walker.current()->setPreferredLogicalWidthsDirty(true);
3539#endif
commit-queue@webkit.org1acd7232021-10-12 20:43:49 +00003540 m_lineLayout = std::monostate();
antti@apple.com467972e2021-02-22 15:30:26 +00003541 setLineLayoutPath(path);
zalan@apple.comfbd3dc8f2022-01-11 03:21:20 +00003542 if (selfNeedsLayout() || normalChildNeedsLayout())
zalan@apple.comde191042017-06-06 19:35:56 +00003543 return;
3544 // FIXME: We should just kick off a subtree layout here (if needed at all) see webkit.org/b/172947.
3545 setNeedsLayout();
antti@apple.com9e891c82014-05-22 06:12:34 +00003546 return;
3547 }
antti@apple.com467972e2021-02-22 15:30:26 +00003548 }
antti@apple.com9e891c82014-05-22 06:12:34 +00003549 ASSERT_NOT_REACHED();
3550}
3551
antti@apple.com1880e712019-11-26 20:15:39 +00003552#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
antti@apple.com561f2f72020-10-26 20:23:48 +00003553void RenderBlockFlow::layoutModernLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com1880e712019-11-26 20:15:39 +00003554{
antti@apple.com3da16952020-10-24 13:46:57 +00003555 bool needsUpdateReplacedDimensions = false;
3556
antti@apple.com561f2f72020-10-26 20:23:48 +00003557 if (!modernLineLayout()) {
antti@apple.comd4dda742019-12-03 15:41:43 +00003558 m_lineLayout = makeUnique<LayoutIntegration::LineLayout>(*this);
antti@apple.com3da16952020-10-24 13:46:57 +00003559 needsUpdateReplacedDimensions = true;
3560 }
antti@apple.com1880e712019-11-26 20:15:39 +00003561
antti@apple.com561f2f72020-10-26 20:23:48 +00003562 auto& layoutFormattingContextLineLayout = *this->modernLineLayout();
zalan@apple.comc4325752022-03-10 22:51:11 +00003563 layoutFormattingContextLineLayout.updateFormattingRootGeometryAndInvalidate();
antti@apple.com1880e712019-11-26 20:15:39 +00003564
antti@apple.com554f9dc2020-11-27 16:52:48 +00003565 for (auto walker = InlineWalker(*this); !walker.atEnd(); walker.advance()) {
3566 auto& renderer = *walker.current();
zalan@apple.comddc3e192021-08-21 01:45:09 +00003567 if (relayoutChildren || (is<RenderBox>(renderer) && downcast<RenderBox>(renderer).hasRelativeDimensions()))
antti@apple.com3da16952020-10-24 13:46:57 +00003568 renderer.setNeedsLayout(MarkOnlyThis);
zalan@apple.comddc3e192021-08-21 01:45:09 +00003569
antti@apple.com3da16952020-10-24 13:46:57 +00003570 if (!renderer.needsLayout() && !needsUpdateReplacedDimensions)
antti@apple.com1f20ffe2020-10-16 17:52:20 +00003571 continue;
antti@apple.com3da16952020-10-24 13:46:57 +00003572
antti@apple.com1f20ffe2020-10-16 17:52:20 +00003573 if (is<RenderReplaced>(renderer)) {
3574 auto& replaced = downcast<RenderReplaced>(renderer);
3575 replaced.layoutIfNeeded();
3576 layoutFormattingContextLineLayout.updateReplacedDimensions(replaced);
3577 continue;
3578 }
zalan@apple.com9983d5e2022-03-11 16:44:43 +00003579 if (is<RenderTable>(renderer)) {
3580 auto& inlineTable = downcast<RenderTable>(renderer);
3581 inlineTable.layoutIfNeeded();
3582 layoutFormattingContextLineLayout.updateInlineTableDimensions(inlineTable);
3583 continue;
3584 }
zalan@apple.comc4325752022-03-10 22:51:11 +00003585 if (is<RenderListMarker>(renderer)) {
3586 auto& marker = downcast<RenderListMarker>(renderer);
3587 marker.layoutIfNeeded();
3588 layoutFormattingContextLineLayout.updateListMarkerDimensions(marker);
3589 continue;
3590 }
3591 if (is<RenderListItem>(renderer)) {
3592 auto& listItem = downcast<RenderListItem>(renderer);
3593 listItem.layoutIfNeeded();
3594 layoutFormattingContextLineLayout.updateListItemDimensions(listItem);
3595 continue;
3596 }
antti@apple.combb78d9a2020-10-26 13:58:58 +00003597 if (is<RenderBlock>(renderer)) {
3598 auto& block = downcast<RenderBlock>(renderer);
3599 block.layoutIfNeeded();
zalan@apple.com24f44fd2020-11-14 17:38:37 +00003600 ASSERT(block.style().display() == DisplayType::InlineBlock);
3601 layoutFormattingContextLineLayout.updateInlineBlockDimensions(block);
antti@apple.combb78d9a2020-10-26 13:58:58 +00003602 continue;
3603 }
3604
zalan@apple.com6e326602020-12-25 21:46:14 +00003605 if (is<RenderLineBreak>(renderer)) {
3606 layoutFormattingContextLineLayout.updateLineBreakBoxDimensions(downcast<RenderLineBreak>(renderer));
3607 renderer.clearNeedsLayout();
3608 continue;
3609 }
3610
zalan@apple.com7023f032020-12-26 15:22:08 +00003611 if (is<RenderInline>(renderer)) {
3612 layoutFormattingContextLineLayout.updateInlineBoxDimensions(downcast<RenderInline>(renderer));
3613 renderer.clearNeedsLayout();
3614 continue;
3615 }
3616
antti@apple.com1880e712019-11-26 20:15:39 +00003617 renderer.clearNeedsLayout();
zalan@apple.com02a0c952020-04-06 23:34:51 +00003618 }
antti@apple.com1880e712019-11-26 20:15:39 +00003619
antti@apple.combeb04982021-08-17 14:11:22 +00003620 auto contentBoxTop = borderAndPaddingBefore();
3621
3622 auto computeContentHeight = [&] {
3623 if (!hasLines() && hasLineIfEmpty())
3624 return lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
3625
3626 return layoutFormattingContextLineLayout.contentLogicalHeight();
3627 };
3628
3629 auto computeBorderBoxBottom = [&] {
3630 auto contentBoxBottom = contentBoxTop + computeContentHeight();
3631 return contentBoxBottom + borderAndPaddingAfter();
3632 };
3633
3634 auto oldBorderBoxBottom = computeBorderBoxBottom();
3635
antti@apple.comd4dda742019-12-03 15:41:43 +00003636 layoutFormattingContextLineLayout.layout();
antti@apple.com1880e712019-11-26 20:15:39 +00003637
antti@apple.com67db9ea2020-09-23 04:39:06 +00003638 if (view().frameView().layoutContext().layoutState()->isPaginated())
antti@apple.com2943bef2020-10-21 16:21:04 +00003639 layoutFormattingContextLineLayout.adjustForPagination();
antti@apple.com67db9ea2020-09-23 04:39:06 +00003640
antti@apple.combeb04982021-08-17 14:11:22 +00003641 auto newBorderBoxBottom = computeBorderBoxBottom();
antti@apple.com1ebf7e12019-12-03 10:51:46 +00003642
zalan@apple.com7b374f82020-01-05 14:50:08 +00003643 repaintLogicalTop = contentBoxTop;
antti@apple.combeb04982021-08-17 14:11:22 +00003644 repaintLogicalBottom = std::max(oldBorderBoxBottom, newBorderBoxBottom);
3645
zalan@apple.com33b5dc62022-04-09 17:55:18 +00003646 auto inflateRepaintTopAndBottomWithInkOverflow = [&] {
zalan@apple.com27da2592022-04-12 01:30:11 +00003647 if (!layoutFormattingContextLineLayout.hasVisualOverflow())
zalan@apple.com33b5dc62022-04-09 17:55:18 +00003648 return;
zalan@apple.com27da2592022-04-12 01:30:11 +00003649 for (auto lineBox = InlineIterator::firstLineBoxFor(*this); lineBox; lineBox.traverseNext()) {
3650 repaintLogicalTop = std::min(repaintLogicalTop, LayoutUnit { lineBox->inkOverflowTop() });
3651 repaintLogicalBottom = std::max(repaintLogicalBottom, LayoutUnit { lineBox->inkOverflowBottom() });
zalan@apple.com33b5dc62022-04-09 17:55:18 +00003652 }
3653 };
3654 inflateRepaintTopAndBottomWithInkOverflow();
3655
antti@apple.combeb04982021-08-17 14:11:22 +00003656 setLogicalHeight(newBorderBoxBottom);
antti@apple.com1880e712019-11-26 20:15:39 +00003657}
3658#endif
3659
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003660#if ENABLE(TREE_DEBUGGING)
simon.fraser@apple.com10335f52021-01-26 22:20:09 +00003661void RenderBlockFlow::outputFloatingObjects(WTF::TextStream& stream, int depth) const
3662{
3663 if (!floatingObjectSet())
3664 return;
3665
3666 for (auto& floatingObject : *floatingObjectSet()) {
3667 int printedCharacters = 0;
3668 while (++printedCharacters <= depth * 2)
3669 stream << " ";
3670
3671 stream << " ";
3672 stream << "floating object " << *floatingObject;
3673 stream.nextLine();
3674 }
3675}
3676
antti@apple.com379e81d2021-06-01 17:22:45 +00003677void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const LegacyInlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003678{
zalan@apple.com385d2492020-10-29 13:17:05 +00003679#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
3680 if (auto* modernLineLayout = this->modernLineLayout()) {
3681 modernLineLayout->outputLineTree(stream, depth);
3682 return;
3683 }
3684#endif
antti@apple.com903292a2021-06-02 16:20:15 +00003685 for (const LegacyRootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.com360de752017-07-06 21:13:24 +00003686 root->outputLineTreeAndMark(stream, markedBox, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003687}
3688#endif
3689
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003690RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3691{
3692 if (hasRareBlockFlowData())
3693 return *m_rareBlockFlowData;
3694 materializeRareBlockFlowData();
3695 return *m_rareBlockFlowData;
3696}
3697
3698void RenderBlockFlow::materializeRareBlockFlowData()
3699{
3700 ASSERT(!hasRareBlockFlowData());
ysuzuki@apple.com1d8e24d2019-08-19 06:59:40 +00003701 m_rareBlockFlowData = makeUnique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003702}
3703
dbates@webkit.org102013c2016-09-26 21:51:25 +00003704#if ENABLE(TEXT_AUTOSIZING)
darin@apple.com5917cb12017-11-23 17:32:42 +00003705
cdumez@apple.com83102df2016-05-19 19:09:41 +00003706static inline bool isVisibleRenderText(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003707{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003708 if (!is<RenderText>(renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003709 return false;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003710
3711 auto& renderText = downcast<RenderText>(renderer);
darin@apple.com5917cb12017-11-23 17:32:42 +00003712 return !renderText.linesBoundingBox().isEmpty() && !renderText.text().isAllSpecialCharacters<isHTMLSpace>();
aestes@apple.com6751d842014-01-12 02:51:25 +00003713}
3714
cdumez@apple.com83102df2016-05-19 19:09:41 +00003715static inline bool resizeTextPermitted(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003716{
3717 // 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 +00003718 for (auto* ancestor = renderer.parent(); ancestor; ancestor = ancestor->parent()) {
aestes@apple.com6751d842014-01-12 02:51:25 +00003719 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.com83102df2016-05-19 19:09:41 +00003720 if (is<HTMLElement>(ancestor->element()) && !ancestor->element()->isInShadowTree()) {
3721 auto& element = downcast<HTMLElement>(*ancestor->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003722 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003723 }
aestes@apple.com6751d842014-01-12 02:51:25 +00003724 }
3725 return true;
3726}
3727
cdumez@apple.com83102df2016-05-19 19:09:41 +00003728static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject& renderer)
aestes@apple.com6751d842014-01-12 02:51:25 +00003729{
cdumez@apple.com83102df2016-05-19 19:09:41 +00003730 if (!renderer.isRenderBlock())
aestes@apple.com6751d842014-01-12 02:51:25 +00003731 return true;
cdumez@apple.com83102df2016-05-19 19:09:41 +00003732 if (renderer.isListItem())
mmaxfield@apple.com87d31e02021-02-12 21:31:41 +00003733 return renderer.style().height().type() != LengthType::Fixed;
aestes@apple.com6751d842014-01-12 02:51:25 +00003734 return false;
3735}
3736
timothy_horton@apple.com117a5f82018-02-19 18:47:30 +00003737// For now, we auto size single lines of text the same as multiple lines.
3738// We've been experimenting with low values for single lines of text.
3739static inline float oneLineTextMultiplier(RenderObject& renderer, float specifiedSize)
aestes@apple.com6751d842014-01-12 02:51:25 +00003740{
timothy_horton@apple.com117a5f82018-02-19 18:47:30 +00003741 const float coefficient = renderer.settings().oneLineTextMultiplierCoefficient();
3742 return std::max((1.0f / log10f(specifiedSize) * coefficient), 1.0f);
aestes@apple.com6751d842014-01-12 02:51:25 +00003743}
3744
timothy_horton@apple.com117a5f82018-02-19 18:47:30 +00003745static inline float textMultiplier(RenderObject& renderer, float specifiedSize)
aestes@apple.com6751d842014-01-12 02:51:25 +00003746{
timothy_horton@apple.com117a5f82018-02-19 18:47:30 +00003747 const float coefficient = renderer.settings().multiLineTextMultiplierCoefficient();
3748 return std::max((1.0f / log10f(specifiedSize) * coefficient), 1.0f);
aestes@apple.com6751d842014-01-12 02:51:25 +00003749}
3750
mmaxfield@apple.com59146a72019-05-29 02:27:20 +00003751void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
aestes@apple.com6751d842014-01-12 02:51:25 +00003752{
simon.fraser@apple.com36676e52016-05-07 00:05:58 +00003753 LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
3754
aestes@apple.com6751d842014-01-12 02:51:25 +00003755 // Don't do any work if the block is smaller than the visible area.
mmaxfield@apple.com59146a72019-05-29 02:27:20 +00003756 if (visibleWidth >= width())
aestes@apple.com6751d842014-01-12 02:51:25 +00003757 return;
3758
zalan@apple.com00b1fee2022-04-10 02:59:35 +00003759 unsigned lineCount = m_lineCountForTextAutosizing;
3760 if (lineCount == NOT_SET) {
3761 if (style().visibility() != Visibility::Visible)
aestes@apple.com6751d842014-01-12 02:51:25 +00003762 lineCount = NO_LINE;
zalan@apple.com00b1fee2022-04-10 02:59:35 +00003763 else {
3764 size_t lineCountInBlock = 0;
3765 if (childrenInline())
3766 lineCountInBlock = this->lineCount();
3767 else {
3768 for (auto& listItem : childrenOfType<RenderListItem>(*this)) {
zalan@apple.com93658f62022-04-10 21:56:21 +00003769 if (!listItem.childrenInline() || listItem.style().visibility() != Visibility::Visible)
3770 continue;
zalan@apple.com00b1fee2022-04-10 02:59:35 +00003771 lineCountInBlock += listItem.lineCount();
3772 if (lineCountInBlock > 1)
3773 break;
3774 }
3775 }
3776 lineCount = !lineCountInBlock ? NO_LINE : lineCountInBlock == 1 ? ONE_LINE : MULTI_LINE;
3777 }
3778 }
3779
aestes@apple.com6751d842014-01-12 02:51:25 +00003780 ASSERT(lineCount != NOT_SET);
3781 if (lineCount == NO_LINE)
3782 return;
3783
3784 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3785 float scale = visibleWidth / actualWidth;
3786 float minFontSize = roundf(size / scale);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003787
3788 for (auto* descendant = RenderObjectTraversal::firstChild(*this); descendant; ) {
3789 if (!isNonBlocksOrNonFixedHeightListItems(*descendant)) {
3790 descendant = RenderObjectTraversal::nextSkippingChildren(*descendant, this);
3791 continue;
aestes@apple.com6751d842014-01-12 02:51:25 +00003792 }
cdumez@apple.com83102df2016-05-19 19:09:41 +00003793 if (!isVisibleRenderText(*descendant) || !resizeTextPermitted(*descendant)) {
3794 descendant = RenderObjectTraversal::next(*descendant, this);
3795 continue;
3796 }
3797
3798 auto& text = downcast<RenderText>(*descendant);
3799 auto& oldStyle = text.style();
3800 auto& fontDescription = oldStyle.fontDescription();
3801 float specifiedSize = fontDescription.specifiedSize();
3802 float scaledSize = roundf(specifiedSize * scale);
mmaxfield@apple.com59146a72019-05-29 02:27:20 +00003803 if (scaledSize > 0 && scaledSize < minFontSize) {
cdumez@apple.com83102df2016-05-19 19:09:41 +00003804 // 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.
3805 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3806 if (m_lineCountForTextAutosizing == NOT_SET)
3807 m_lineCountForTextAutosizing = lineCount;
3808 if (m_widthForTextAutosizing == -1)
3809 m_widthForTextAutosizing = actualWidth;
3810
mmaxfield@apple.com59146a72019-05-29 02:27:20 +00003811 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(text, specifiedSize) : textMultiplier(text, specifiedSize);
3812 float candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
mmaxfield@apple.comac71afa2019-04-26 06:33:56 +00003813
commit-queue@webkit.orgf2872372019-04-26 18:32:41 +00003814 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
antti@apple.com4918b4d2017-08-14 13:20:47 +00003815 document().textAutoSizing().addTextNode(*text.textNode(), candidateNewSize);
cdumez@apple.com83102df2016-05-19 19:09:41 +00003816 }
3817
3818 descendant = RenderObjectTraversal::nextSkippingChildren(text, this);
aestes@apple.com6751d842014-01-12 02:51:25 +00003819 }
3820}
darin@apple.com5917cb12017-11-23 17:32:42 +00003821
dbates@webkit.org102013c2016-09-26 21:51:25 +00003822#endif // ENABLE(TEXT_AUTOSIZING)
aestes@apple.com6751d842014-01-12 02:51:25 +00003823
hyatt@apple.com80914862017-03-06 18:00:35 +00003824void RenderBlockFlow::layoutExcludedChildren(bool relayoutChildren)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003825{
hyatt@apple.com80914862017-03-06 18:00:35 +00003826 RenderBlock::layoutExcludedChildren(relayoutChildren);
3827
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003828 auto* fragmentedFlow = multiColumnFlow();
3829 if (!fragmentedFlow)
hyatt@apple.com80914862017-03-06 18:00:35 +00003830 return;
3831
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003832 fragmentedFlow->setIsExcludedFromNormalLayout(true);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003833
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003834 setLogicalTopForChild(*fragmentedFlow, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003835
3836 if (relayoutChildren)
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003837 fragmentedFlow->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003838
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003839 if (fragmentedFlow->needsLayout()) {
3840 for (RenderMultiColumnSet* columnSet = fragmentedFlow->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3841 columnSet->prepareForLayout(!fragmentedFlow->inBalancingPass());
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003842
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003843 fragmentedFlow->invalidateFragments(MarkOnlyThis);
3844 fragmentedFlow->setNeedsHeightsRecalculation(true);
3845 fragmentedFlow->layout();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003846 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003847 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3848 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3849 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3850 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3851 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3852 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3853 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3854 // runs get deleted right after every pass.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003855 fragmentedFlow->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003856 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003857 determineLogicalLeftPositionForChild(*fragmentedFlow);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003858}
3859
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003860void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003861{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003862 // If we don't use columns or flow threads, then bail.
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003863 if (!isRenderFragmentedFlow() && !multiColumnFlow())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003864 return;
3865
3866 // 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 +00003867 if (RenderMultiColumnFlow* fragmentedFlow = multiColumnFlow()) {
zalan@apple.com53e79072016-12-12 20:17:50 +00003868 LayoutUnit newColumnHeight;
3869 if (hasDefiniteLogicalHeight() || view().frameView().pagination().mode != Pagination::Unpaginated) {
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00003870 auto computedValues = computeLogicalHeight(0_lu, logicalTop());
zalan@apple.com53e79072016-12-12 20:17:50 +00003871 newColumnHeight = std::max<LayoutUnit>(computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(), 0);
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003872 if (fragmentedFlow->columnHeightAvailable() != newColumnHeight)
zalan@apple.com53e79072016-12-12 20:17:50 +00003873 relayoutChildren = true;
3874 }
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003875 fragmentedFlow->setColumnHeightAvailable(newColumnHeight);
3876 } else if (is<RenderFragmentedFlow>(*this)) {
3877 RenderFragmentedFlow& fragmentedFlow = downcast<RenderFragmentedFlow>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003878
3879 // FIXME: This is a hack to always make sure we have a page logical height, if said height
antti@apple.comf41183e2018-12-07 20:10:14 +00003880 // is known. The page logical height thing in RenderLayoutState is meaningless for flow
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003881 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3882 // thread), but as long as it is used universally as a means to determine whether page
3883 // height is known or not, we need this. Page height is unknown when column balancing is
3884 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3885 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3886 // 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 +00003887 // hack once the old multicol implementation is gone (see also RenderView::pushLayoutStateForPagination).
ross.kirsling@sony.coma10d10c2018-11-23 20:47:11 +00003888 pageLogicalHeight = fragmentedFlow.isPageLogicalHeightKnown() ? 1_lu : 0_lu;
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003889
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003890 pageLogicalHeightChanged = fragmentedFlow.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003891 }
3892}
3893
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003894bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
zalan@apple.com809f4872016-12-08 18:20:01 +00003895{
3896 return willCreateColumns(desiredColumnCount);
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003897}
3898
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003899void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3900{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003901 ASSERT(!!multiColumnFlow() == requiresColumns(count));
3902 if (!multiColumnFlow())
antti@apple.com411949d2017-08-30 17:28:10 +00003903 return;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003904 multiColumnFlow()->setColumnCountAndWidth(count, width);
3905 multiColumnFlow()->setProgressionIsInline(style().hasInlineColumnAxis());
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00003906 multiColumnFlow()->setProgressionIsReversed(style().columnProgression() == ColumnProgression::Reverse);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003907}
3908
cdumez@apple.com78141732014-11-04 23:00:48 +00003909void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003910{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003911 if (!multiColumnFlow())
hyatt@apple.com86919862014-01-27 16:27:45 +00003912 return;
3913
3914 bool needsLayout = false;
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003915 bool oldProgressionIsInline = multiColumnFlow()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003916 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003917 if (oldProgressionIsInline != newProgressionIsInline) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003918 multiColumnFlow()->setProgressionIsInline(newProgressionIsInline);
hyatt@apple.com86919862014-01-27 16:27:45 +00003919 needsLayout = true;
3920 }
3921
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003922 bool oldProgressionIsReversed = multiColumnFlow()->progressionIsReversed();
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00003923 bool newProgressionIsReversed = style.columnProgression() == ColumnProgression::Reverse;
hyatt@apple.com86919862014-01-27 16:27:45 +00003924 if (oldProgressionIsReversed != newProgressionIsReversed) {
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003925 multiColumnFlow()->setProgressionIsReversed(newProgressionIsReversed);
hyatt@apple.com86919862014-01-27 16:27:45 +00003926 needsLayout = true;
3927 }
3928
3929 if (needsLayout)
3930 setNeedsLayoutAndPrefWidthsRecalc();
3931}
3932
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003933LayoutUnit RenderBlockFlow::computedColumnWidth() const
3934{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003935 if (multiColumnFlow())
3936 return multiColumnFlow()->computedColumnWidth();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003937 return contentLogicalWidth();
3938}
3939
3940unsigned RenderBlockFlow::computedColumnCount() const
3941{
hyatt@apple.com4e0bf862017-09-27 20:54:17 +00003942 if (multiColumnFlow())
3943 return multiColumnFlow()->computedColumnCount();
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003944
3945 return 1;
3946}
3947
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003948bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3949{
3950 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00003951 if (!multiColumnFlow() || style().columnProgression() == ColumnProgression::Normal)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003952 return hasTopOverflow;
3953
3954 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3955 hasTopOverflow = !hasTopOverflow;
3956
3957 return hasTopOverflow;
3958}
3959
3960bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3961{
3962 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
commit-queue@webkit.orgeea2d6a2018-05-25 01:42:36 +00003963 if (!multiColumnFlow() || style().columnProgression() == ColumnProgression::Normal)
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003964 return hasLeftOverflow;
3965
3966 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3967 hasLeftOverflow = !hasLeftOverflow;
3968
3969 return hasLeftOverflow;
3970}
3971
zalan@apple.comac6956c2014-09-05 14:18:06 +00003972struct InlineMinMaxIterator {
3973/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3974 inline min/max width calculations. Note the following about the way it walks:
3975 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3976 (2) We do not drill into the children of floats or replaced elements, since you can't break
3977 in the middle of such an element.
3978 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3979 distinct borders/margin/padding that contribute to the min/max width.
3980*/
3981 const RenderBlockFlow& parent;
3982 RenderObject* current;
3983 bool endOfInline;
3984 bool initial;
3985
3986 InlineMinMaxIterator(const RenderBlockFlow& p)
3987 : parent(p)
3988 , current(nullptr)
3989 , endOfInline(false)
3990 , initial(true)
3991 { }
3992
3993 RenderObject* next();
3994};
3995
3996RenderObject* InlineMinMaxIterator::next()
3997{
3998 RenderObject* result = nullptr;
3999 bool oldEndOfInline = endOfInline;
4000 endOfInline = false;
4001 do {
darin@apple.com8152c8ba2022-01-15 22:29:21 +00004002 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplacedOrInlineBlock() && !current->isOutOfFlowPositioned()))
zalan@apple.comac6956c2014-09-05 14:18:06 +00004003 result = current->firstChildSlow();
4004 else if (initial) {
4005 result = parent.firstChild();
4006 initial = false;
4007 }
4008
4009 if (!result) {
4010 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4011 if (!oldEndOfInline && current && current->isRenderInline()) {
4012 result = current;
4013 endOfInline = true;
4014 break;
4015 }
4016
4017 while (current && current != &parent) {
4018 result = current->nextSibling();
4019 if (result)
4020 break;
4021 current = current->parent();
4022 if (current && current != &parent && current->isRenderInline()) {
4023 result = current;
4024 endOfInline = true;
4025 break;
4026 }
4027 }
4028 }
4029
4030 if (!result)
4031 break;
4032
darin@apple.com8152c8ba2022-01-15 22:29:21 +00004033 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplacedOrInlineBlock() || result->isRenderInline()))
zalan@apple.comac6956c2014-09-05 14:18:06 +00004034 break;
4035
4036 current = result;
4037 result = nullptr;
4038 } while (current || current == &parent);
4039 // Update our position.
4040 current = result;
4041 return result;
4042}
4043
4044static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4045{
mmaxfield@apple.com87d31e02021-02-12 21:31:41 +00004046 if (cssUnit.type() != LengthType::Auto)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004047 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4048 return 0;
4049}
4050
4051static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4052{
4053 const RenderStyle& childStyle = child.style();
4054 if (endOfInline) {
4055 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4056 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4057 child.borderEnd();
4058 }
4059 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4060 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4061 child.borderStart();
4062}
4063
4064static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4065{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004066 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004067 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004068 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004069 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004070 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
mmaxfield@apple.com21a4dcb2016-03-13 00:36:59 +00004071 float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004072 inlineMax -= spaceWidth + font.wordSpacing();
4073 if (inlineMin > inlineMax)
4074 inlineMin = inlineMax;
4075 }
4076}
4077
4078static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4079{
4080 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4081}
4082
4083void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4084{
simon.fraser@apple.come8ee49b2022-05-06 17:10:31 +00004085 ASSERT(!shouldApplyInlineSizeContainment());
antti@apple.com38fd60c2022-02-09 12:42:22 +00004086
antti@apple.com5072de92021-11-02 16:01:26 +00004087#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
4088 if (const_cast<RenderBlockFlow&>(*this).tryComputePreferredWidthsUsingModernPath(minLogicalWidth, maxLogicalWidth))
4089 return;
4090#endif
4091
zalan@apple.comac6956c2014-09-05 14:18:06 +00004092 float inlineMax = 0;
4093 float inlineMin = 0;
4094
4095 const RenderStyle& styleToUse = style();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004096 // If we are at the start of a line, we want to ignore all white-space.
4097 // Also strip spaces if we previously had text that ended in a trailing space.
4098 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004099 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004100
4101 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4102 // very specific cirucumstances (in order to match common WinIE renderings).
4103 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4104 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4105
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004106 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004107
4108 InlineMinMaxIterator childIterator(*this);
4109
4110 // Only gets added to the max preffered width once.
4111 bool addedTextIndent = false;
4112 // Signals the text indent was more negative than the min preferred width
4113 bool hasRemainingNegativeTextIndent = false;
4114
zalan@apple.com4624e142020-04-29 17:52:30 +00004115 auto textIndent = LayoutUnit { };
4116 if (styleToUse.textIndent().isFixed())
4117 textIndent = LayoutUnit { styleToUse.textIndent().value() };
4118 else if (auto* containingBlock = this->containingBlock(); containingBlock && containingBlock->style().logicalWidth().isFixed()) {
4119 // At this point of the shrink-to-fit computatation, we don't have a used value for the containing block width
4120 // (that's exactly to what we try to contribute here) unless the computed value is fixed.
4121 textIndent = minimumValueForLength(styleToUse.textIndent(), containingBlock->style().logicalWidth().value());
4122 }
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00004123 RenderObject* previousFloat = 0;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004124 bool isPrevChildInlineFlow = false;
4125 bool shouldBreakLineAfterText = false;
commit-queue@webkit.org02cb0002018-05-28 00:49:21 +00004126 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation().contains(HangingPunctuation::First);
4127 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation().contains(HangingPunctuation::Last);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004128 RenderText* lastText = nullptr;
4129
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004130 bool addedStartPunctuationHang = false;
4131
zalan@apple.comac6956c2014-09-05 14:18:06 +00004132 while (RenderObject* child = childIterator.next()) {
darin@apple.com8152c8ba2022-01-15 22:29:21 +00004133 bool autoWrap = child->isReplacedOrInlineBlock() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004134 child->style().autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004135 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004136 // Step One: determine whether or not we need to terminate our current line.
4137 // Each discrete chunk can become the new min-width, if it is the widest chunk
4138 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004139
4140 // Children fall into three categories:
4141 // (1) An inline flow object. These objects always have a min/max of 0,
4142 // and are included in the iteration solely so that their margins can
4143 // be added in.
4144 //
4145 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4146 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004147 // we need to break the current line, and then add in our own margins and min/max
4148 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004149 //
4150 // (3) A text object. Text runs can have breakable characters at the start,
4151 // the middle or the end. They may also lose whitespace off the front if
4152 // we're already ignoring whitespace. In order to compute accurate min-width
4153 // information, we need three pieces of information.
4154 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4155 // starts with whitespace.
4156 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4157 // ends with whitespace.
4158 // (c) the min/max width of the string (trimmed for whitespace).
4159 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004160 // If the text string starts with whitespace, then we need to terminate our current line
4161 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004162 //
4163 // If the text string has a breakable character in the middle, but didn't start
4164 // with whitespace, then we add the width of the first non-breakable run and
4165 // then end the current line. We then need to use the intermediate min/max width
4166 // values (if any of them are larger than our current min/max). We then look at
4167 // the width of the last non-breakable run and use that to start a new line
4168 // (unless we end in whitespace).
4169 const RenderStyle& childStyle = child->style();
4170 float childMin = 0;
4171 float childMax = 0;
4172
4173 if (!child->isText()) {
4174 if (child->isLineBreakOpportunity()) {
4175 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4176 inlineMin = 0;
4177 continue;
4178 }
4179 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004180 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004181 // Add in padding/border/margin from the appropriate side of
4182 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004183 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004184 childMin += bpm;
4185 childMax += bpm;
4186
4187 inlineMin += childMin;
4188 inlineMax += childMax;
4189
4190 child->setPreferredLogicalWidthsDirty(false);
4191 } else {
4192 // Inline replaced elts add in their margins to their min/max values.
hyatt@apple.com14520e42016-04-20 18:01:40 +00004193 if (!child->isFloating())
4194 lastText = nullptr;
ross.kirsling@sony.combd744282018-11-18 03:14:31 +00004195 LayoutUnit margins;
svillar@igalia.com18bfb8f2021-12-13 17:19:12 +00004196 Length startMargin = childStyle.marginStartUsing(&style());
4197 Length endMargin = childStyle.marginEndUsing(&style());
zalan@apple.comac6956c2014-09-05 14:18:06 +00004198 if (startMargin.isFixed())
4199 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4200 if (endMargin.isFixed())
4201 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4202 childMin += margins.ceilToFloat();
4203 childMax += margins.ceilToFloat();
4204 }
4205 }
4206
cdumez@apple.comf8022152014-10-15 00:29:51 +00004207 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004208 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004209 // Terminate the current line as far as minwidth is concerned.
hyatt@apple.com247170f2017-02-28 16:23:15 +00004210 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4211 computeChildPreferredLogicalWidths(*child, childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth);
4212 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4213 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004214
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00004215 bool clearPreviousFloat = false;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004216 if (child->isFloating()) {
commit-queue@webkit.orgdfd8c4d2021-04-18 01:03:18 +00004217 auto childClearValue = RenderStyle::usedClear(*child);
4218 if (previousFloat) {
4219 auto previousFloatValue = RenderStyle::usedFloat(*previousFloat);
4220 clearPreviousFloat =
4221 (previousFloatValue == UsedFloat::Left && (childClearValue == UsedClear::Left || childClearValue == UsedClear::Both))
4222 || (previousFloatValue == UsedFloat::Right && (childClearValue == UsedClear::Right || childClearValue == UsedClear::Both));
4223 }
4224 previousFloat = child;
4225 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004226
4227 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
antti@apple.comae85e112017-08-31 23:27:02 +00004228 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004229 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4230 inlineMin = 0;
4231 }
4232
4233 // If we're supposed to clear the previous float, then terminate maxwidth as well.
antti@apple.comae85e112017-08-31 23:27:02 +00004234 if (clearPreviousFloat) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004235 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4236 inlineMax = 0;
4237 }
4238
4239 // Add in text-indent. This is added in only once.
antti@apple.comae85e112017-08-31 23:27:02 +00004240 if (!addedTextIndent && !child->isFloating()) {
ross.kirsling@sony.com80414652019-05-21 01:36:11 +00004241 LayoutUnit ceiledIndent { textIndent.ceilToFloat() };
zalan@apple.comac6956c2014-09-05 14:18:06 +00004242 childMin += ceiledIndent;
4243 childMax += ceiledIndent;
4244
4245 if (childMin < 0)
4246 textIndent = LayoutUnit::fromFloatCeil(childMin);
4247 else
4248 addedTextIndent = true;
4249 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004250
antti@apple.comae85e112017-08-31 23:27:02 +00004251 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating())
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004252 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004253
4254 // Add our width to the max.
4255 inlineMax += std::max<float>(0, childMax);
4256
antti@apple.comae85e112017-08-31 23:27:02 +00004257 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText))) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004258 if (child->isFloating())
4259 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4260 else
4261 inlineMin += childMin;
4262 } else {
4263 // Now check our line.
4264 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4265
4266 // Now start a new line.
antti@apple.comae85e112017-08-31 23:27:02 +00004267 inlineMin = 0;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004268 }
4269
4270 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4271 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4272 inlineMin = 0;
4273 }
4274
4275 // We are no longer stripping whitespace at the start of a line.
4276 if (!child->isFloating()) {
4277 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004278 trailingSpaceChild = nullptr;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004279 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004280 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004281 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004282 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004283 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004284
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004285 if (renderText.style().hasTextCombine() && renderText.isCombineText())
zalan@apple.com6cad78f2017-09-19 20:28:29 +00004286 downcast<RenderCombineText>(renderText).combineTextIfNeeded();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004287
4288 // Determine if we have a breakable character. Pass in
4289 // whether or not we should ignore any spaces at the front
4290 // of the string. If those are going to be stripped out,
4291 // then they shouldn't be considered in the breakable char
4292 // check.
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004293 bool strippingBeginWS = stripFrontSpaces;
darin@apple.com5917cb12017-11-23 17:32:42 +00004294 auto widths = renderText.trimmedPreferredWidths(inlineMax, stripFrontSpaces);
4295
4296 childMin = widths.min;
4297 childMax = widths.max;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004298
4299 // This text object will not be rendered, but it may still provide a breaking opportunity.
darin@apple.com5917cb12017-11-23 17:32:42 +00004300 if (!widths.hasBreak && !childMax) {
4301 if (autoWrap && (widths.beginWS || widths.endWS)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004302 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4303 inlineMin = 0;
4304 }
4305 continue;
4306 }
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004307
4308 lastText = &renderText;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004309
4310 if (stripFrontSpaces)
4311 trailingSpaceChild = child;
4312 else
4313 trailingSpaceChild = 0;
4314
4315 // Add in text-indent. This is added in only once.
4316 float ti = 0;
4317 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4318 ti = textIndent.ceilToFloat();
4319 childMin += ti;
darin@apple.com5917cb12017-11-23 17:32:42 +00004320 widths.beginMin += ti;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004321
4322 // It the text indent negative and larger than the child minimum, we re-use the remainder
4323 // in future minimum calculations, but using the negative value again on the maximum
4324 // will lead to under-counting the max pref width.
4325 if (!addedTextIndent) {
4326 childMax += ti;
darin@apple.com5917cb12017-11-23 17:32:42 +00004327 widths.beginMax += ti;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004328 addedTextIndent = true;
4329 }
4330
4331 if (childMin < 0) {
4332 textIndent = childMin;
4333 hasRemainingNegativeTextIndent = true;
4334 }
4335 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004336
4337 // See if we have a hanging punctuation situation at the start.
4338 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004339 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4340 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004341 childMin -= hangStartWidth;
darin@apple.com5917cb12017-11-23 17:32:42 +00004342 widths.beginMin -= hangStartWidth;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004343 childMax -= hangStartWidth;
darin@apple.com5917cb12017-11-23 17:32:42 +00004344 widths.beginMax -= hangStartWidth;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004345 addedStartPunctuationHang = true;
4346 }
4347
zalan@apple.comac6956c2014-09-05 14:18:06 +00004348 // If we have no breakable characters at all,
4349 // then this is the easy case. We add ourselves to the current
4350 // min and max and continue.
darin@apple.com5917cb12017-11-23 17:32:42 +00004351 if (!widths.hasBreakableChar)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004352 inlineMin += childMin;
4353 else {
4354 // We have a breakable character. Now we need to know if
4355 // we start and end with whitespace.
darin@apple.com5917cb12017-11-23 17:32:42 +00004356 if (widths.beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004357 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004358 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4359 } else {
darin@apple.com5917cb12017-11-23 17:32:42 +00004360 inlineMin += widths.beginMin;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004361 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4362 childMin -= ti;
4363 }
4364
4365 inlineMin = childMin;
4366
darin@apple.com5917cb12017-11-23 17:32:42 +00004367 if (widths.endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004368 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004369 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4370 inlineMin = 0;
4371 shouldBreakLineAfterText = false;
4372 } else {
4373 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
darin@apple.com5917cb12017-11-23 17:32:42 +00004374 inlineMin = widths.endMin;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004375 shouldBreakLineAfterText = true;
4376 }
4377 }
4378
darin@apple.com5917cb12017-11-23 17:32:42 +00004379 if (widths.hasBreak) {
4380 inlineMax += widths.beginMax;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004381 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4382 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
darin@apple.com5917cb12017-11-23 17:32:42 +00004383 inlineMax = widths.endMax;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004384 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004385 addedStartPunctuationHang = true;
zalan@apple.coma46001c2021-10-03 21:57:12 +00004386 if (widths.endsWithBreak)
4387 stripFrontSpaces = true;
4388
zalan@apple.comac6956c2014-09-05 14:18:06 +00004389 } else
4390 inlineMax += std::max<float>(0, childMax);
4391 }
4392
antti@apple.comae85e112017-08-31 23:27:02 +00004393 // Ignore spaces after a list marker.
4394 if (child->isListMarker())
zalan@apple.comac6956c2014-09-05 14:18:06 +00004395 stripFrontSpaces = true;
4396 } else {
zalan@apple.com37144e62020-11-01 22:03:36 +00004397 if (styleToUse.collapseWhiteSpace())
4398 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004399 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4400 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4401 inlineMin = inlineMax = 0;
4402 stripFrontSpaces = true;
4403 trailingSpaceChild = 0;
4404 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004405 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004406 }
4407
4408 if (!child->isText() && child->isRenderInline())
4409 isPrevChildInlineFlow = true;
4410 else
4411 isPrevChildInlineFlow = false;
4412
4413 oldAutoWrap = autoWrap;
4414 }
4415
4416 if (styleToUse.collapseWhiteSpace())
4417 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004418
darin@apple.com5917cb12017-11-23 17:32:42 +00004419 if (canHangPunctuationAtEnd && lastText && lastText->text().length() > 0) {
4420 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->text().length() - 1;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004421 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4422 inlineMin -= endHangWidth;
4423 inlineMax -= endHangWidth;
4424 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004425
4426 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4427 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4428}
4429
antti@apple.com5072de92021-11-02 16:01:26 +00004430#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
4431bool RenderBlockFlow::tryComputePreferredWidthsUsingModernPath(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
4432{
4433#if ENABLE_MODERN_PREFERRED_WIDTH_COMPUTATION
4434 computeAndSetLineLayoutPath();
4435
4436 // FIXME: Pass the replaced and inline block constrainst to IFC.
4437 auto canUseModernPathForPreferredWidthComputation = [&] {
4438 if (lineLayoutPath() != ModernPath)
4439 return false;
4440 for (auto walker = InlineWalker(*this); !walker.atEnd(); walker.advance()) {
4441 auto& renderer = *walker.current();
4442 if (renderer.isText())
4443 continue;
4444 if (is<RenderLineBreak>(renderer))
4445 continue;
4446#if ENABLE_MODERN_PREFERRED_WIDTH_COMPUTATION_FOR_INLINE_BOXES
4447 if (is<RenderInline>(renderer))
4448 continue;
4449#endif
4450 return false;
4451 }
4452 return true;
4453 };
4454
4455 if (!canUseModernPathForPreferredWidthComputation())
4456 return false;
4457
4458 if (!modernLineLayout())
4459 m_lineLayout = makeUnique<LayoutIntegration::LineLayout>(*this);
4460
zalan@apple.comcc712502021-11-20 14:43:28 +00004461#if ENABLE_MODERN_PREFERRED_WIDTH_COMPUTATION_FOR_INLINE_BOXES
4462 auto& layoutFormattingContextLineLayout = *this->modernLineLayout();
4463 for (auto walker = InlineWalker(*this); !walker.atEnd(); walker.advance()) {
4464 auto& renderer = *walker.current();
4465 if (renderer.isText() || is<RenderLineBreak>(renderer))
4466 continue;
4467 if (is<RenderInline>(renderer)) {
4468 layoutFormattingContextLineLayout.updateInlineBoxDimensions(downcast<RenderInline>(renderer));
4469 continue;
4470 }
4471 // FIXME: Add other, inline level box cases.
4472 ASSERT_NOT_IMPLEMENTED_YET();
4473 }
4474#endif
4475
antti@apple.com5072de92021-11-02 16:01:26 +00004476 std::tie(minLogicalWidth, maxLogicalWidth) = modernLineLayout()->computeIntrinsicWidthConstraints();
zalan@apple.comadb2ec82021-11-17 14:19:54 +00004477 for (auto walker = InlineWalker(*this); !walker.atEnd(); walker.advance())
4478 walker.current()->setPreferredLogicalWidthsDirty(false);
4479 return true;
antti@apple.com5072de92021-11-02 16:01:26 +00004480#else
4481 UNUSED_PARAM(minLogicalWidth);
4482 UNUSED_PARAM(maxLogicalWidth);
4483 return false;
4484#endif
4485}
4486#endif
4487
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004488}
4489// namespace WebCore