blob: 55361a3ee5efec2438afab70e88964725da799a5 [file] [log] [blame]
hyatt@apple.com5388e672013-09-06 20:54:47 +00001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
bfulgham@apple.comb5953432015-02-13 21:56:01 +00005 * Copyright (C) 2003-2015 Apple Inc. All rights reserved.
hyatt@apple.com5388e672013-09-06 20:54:47 +00006 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "RenderBlockFlow.h"
26
weinig@apple.com611b9292013-10-20 22:57:54 +000027#include "Editor.h"
bjonesbe@adobe.com67478092013-09-09 22:18:17 +000028#include "FloatingObjects.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000029#include "Frame.h"
zalan@apple.come36543a2014-07-29 01:45:54 +000030#include "FrameSelection.h"
darin@apple.com15708b12014-03-16 16:38:58 +000031#include "HTMLElement.h"
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000032#include "HitTestLocation.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000033#include "InlineTextBox.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000034#include "LayoutRepainter.h"
simon.fraser@apple.com36676e52016-05-07 00:05:58 +000035#include "Logging.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000036#include "RenderCombineText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000037#include "RenderFlowThread.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000038#include "RenderInline.h"
akling@apple.comf3028052013-11-04 08:46:06 +000039#include "RenderIterator.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000040#include "RenderLayer.h"
zalan@apple.com8bf2a912015-04-10 03:15:50 +000041#include "RenderLineBreak.h"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000042#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000043#include "RenderMarquee.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000044#include "RenderMultiColumnFlowThread.h"
45#include "RenderMultiColumnSet.h"
mihnea@adobe.combe79cf12013-10-17 09:02:19 +000046#include "RenderNamedFlowFragment.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000047#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000048#include "RenderText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000049#include "RenderView.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000050#include "Settings.h"
antti@apple.com940f5872013-10-24 20:31:11 +000051#include "SimpleLineLayoutFunctions.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000052#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000053#include "VisiblePosition.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000054#include <wtf/NeverDestroyed.h>
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000055
hyatt@apple.com5388e672013-09-06 20:54:47 +000056namespace WebCore {
57
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000058bool RenderBlock::s_canPropagateFloatIntoSibling = false;
59
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000060struct SameSizeAsMarginInfo {
61 uint32_t bitfields : 16;
62 LayoutUnit margins[2];
63};
64
65COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000066COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000067
68// Our MarginInfo state used when laying out block children.
hyatt@apple.com9a79c622015-09-15 18:38:18 +000069RenderBlockFlow::MarginInfo::MarginInfo(const RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000070 : m_atBeforeSideOfBlock(true)
71 , m_atAfterSideOfBlock(false)
72 , m_hasMarginBeforeQuirk(false)
73 , m_hasMarginAfterQuirk(false)
74 , m_determinedMarginBeforeQuirk(false)
75 , m_discardMargin(false)
76{
akling@apple.com827be9c2013-10-29 02:58:43 +000077 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000078 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000079 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000080
akling@apple.com827be9c2013-10-29 02:58:43 +000081 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000082
83 // If any height other than auto is specified in CSS, then we don't collapse our bottom
84 // margins with our children's margins. To do otherwise would be to risk odd visual
85 // effects when the children overflow out of the parent block and yet still collapse
86 // with it. We also don't collapse if we have any bottom border/padding.
87 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000088 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000089
weinig@apple.com12840dc2013-10-22 23:59:08 +000090 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000091
weinig@apple.com12840dc2013-10-22 23:59:08 +000092 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000093
weinig@apple.com12840dc2013-10-22 23:59:08 +000094 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
95 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000096}
97
antti@apple.com454418f2016-04-25 19:49:23 +000098RenderBlockFlow::RenderBlockFlow(Element& element, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +000099 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000100#if ENABLE(IOS_TEXT_AUTOSIZING)
101 , m_widthForTextAutosizing(-1)
102 , m_lineCountForTextAutosizing(NOT_SET)
103#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000104{
weinig@apple.com611b9292013-10-20 22:57:54 +0000105 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000106}
107
antti@apple.com454418f2016-04-25 19:49:23 +0000108RenderBlockFlow::RenderBlockFlow(Document& document, RenderStyle&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000109 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000110#if ENABLE(IOS_TEXT_AUTOSIZING)
111 , m_widthForTextAutosizing(-1)
112 , m_lineCountForTextAutosizing(NOT_SET)
113#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000114{
weinig@apple.com611b9292013-10-20 22:57:54 +0000115 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000116}
117
118RenderBlockFlow::~RenderBlockFlow()
119{
120}
121
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000122void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000123{
antti@apple.com454418f2016-04-25 19:49:23 +0000124 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000125 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000126 setChildrenInline(false); // Do this to avoid wrapping inline children that are just going to move into the flow thread.
abucur@adobe.com99757c62014-07-31 13:43:52 +0000127 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000128 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000129 flowThread->populate(); // Called after the flow thread is inserted so that we are reachable by the flow thread.
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000130 setMultiColumnFlowThread(flowThread);
131}
132
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000133void RenderBlockFlow::destroyMultiColumnFlowThread()
134{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000135 multiColumnFlowThread()->evacuateAndDestroy();
136 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000137}
138
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000139void RenderBlockFlow::insertedIntoTree()
140{
141 RenderBlock::insertedIntoTree();
142 createRenderNamedFlowFragmentIfNeeded();
143}
144
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000145void RenderBlockFlow::willBeDestroyed()
146{
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000147 if (renderNamedFlowFragment())
zalan@apple.comfcaf5c22016-01-15 21:49:33 +0000148 setRenderNamedFlowFragment(nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +0000149
weinig@apple.com611b9292013-10-20 22:57:54 +0000150 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
151 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
152 destroyLeftoverChildren();
153
weinig@apple.com611b9292013-10-20 22:57:54 +0000154 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000155 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000156 // We can't wait for RenderBox::destroy to clear the selection,
157 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000158 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000159 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000160
161 // If we are an anonymous block, then our line boxes might have children
162 // that will outlast this block. In the non-anonymous block case those
163 // children will be destroyed by the time we return from this function.
164 if (isAnonymousBlock()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +0000165 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000166 while (auto childBox = box->firstChild())
167 childBox->removeFromParent();
168 }
169 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000170 } else if (parent())
171 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000172 }
173
akling@apple.com31dd4f42013-10-30 22:27:59 +0000174 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000175
dbates@webkit.org34f59002014-05-20 20:34:35 +0000176 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000177
178 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
179 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000180}
181
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000182RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
183{
184 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
185 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
186 // to avoid floats.
187 parentHasFloats = false;
188 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
189 if (is<RenderBlockFlow>(*sibling)) {
190 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
191 if (!siblingBlock.avoidsFloats())
192 return &siblingBlock;
193 }
194 if (sibling->isFloating())
195 parentHasFloats = true;
196 }
197 return nullptr;
198}
199
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000200void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000201{
202 if (m_floatingObjects)
203 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
204
205 HashSet<RenderBox*> oldIntrudingFloatSet;
206 if (!childrenInline() && m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000207 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
208 auto end = floatingObjectSet.end();
209 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
210 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000211 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000212 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000213 }
214 }
215
216 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000217 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000218 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000219 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000220 if (!oldIntrudingFloatSet.isEmpty())
221 markAllDescendantsWithFloatsForLayout();
222 return;
223 }
224
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000225 RendererToFloatInfoMap floatMap;
226
227 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000228 if (childrenInline())
229 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
230 else
231 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000232 }
233
234 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
235 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
236 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000237 bool isBlockInsideInline = isAnonymousInlineBlock();
238 if (!is<RenderBlockFlow>(parent()) && !isBlockInsideInline)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000239 return;
240
robert@webkit.org97037ef2013-11-20 19:26:10 +0000241 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
242 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000243 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(isBlockInsideInline ? *containingBlock() : *parent());
244 bool parentHasFloats = isBlockInsideInline ? parentBlock.containsFloats() : false;
245 RenderBlockFlow* previousBlock = nullptr;
246 if (!isBlockInsideInline)
247 previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000248 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000249 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000250 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000251
252 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000253 if (previousBlock)
254 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000255 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000256 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000257 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000258 }
259
260 // 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 +0000261 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000262 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000263
264 if (childrenInline()) {
265 LayoutUnit changeLogicalTop = LayoutUnit::max();
266 LayoutUnit changeLogicalBottom = LayoutUnit::min();
267 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000268 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
269 auto end = floatingObjectSet.end();
270 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000271 const auto& floatingObject = *it->get();
272 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000273 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000274 if (oldFloatingObject) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000275 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
276 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000277 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000278 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000279 } else {
280 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000281 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
282 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000283 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000284 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000285 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000286 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000287 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
288 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000289 }
290 }
291
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000292 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
293 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
294 oldFloatingObject->originatingLine()->markDirty();
295 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000296 } else {
297 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000298 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000299 }
300 }
301 }
302
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000303 auto end = floatMap.end();
304 for (auto it = floatMap.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000305 const auto& floatingObject = *it->value.get();
306 if (!floatingObject.isDescendant()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000307 changeLogicalTop = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000308 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000309 }
310 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000311
312 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
313 } else if (!oldIntrudingFloatSet.isEmpty()) {
314 // If there are previously intruding floats that no longer intrude, then children with floats
315 // should also get layout because they might need their floating object lists cleared.
316 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
317 markAllDescendantsWithFloatsForLayout();
318 else {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000319 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
320 auto end = floatingObjectSet.end();
321 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
322 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000323 if (!oldIntrudingFloatSet.isEmpty())
324 markAllDescendantsWithFloatsForLayout();
325 }
326 }
327}
328
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000329void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
330{
331 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
332 // The min/max intrinsic widths calculated really tell how much space elements need when
333 // laid out inside the columns. In order to eventually end up with the desired column width,
334 // we need to convert them to values pertaining to the multicol container.
335 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
336 LayoutUnit columnWidth;
337 LayoutUnit colGap = columnGap();
338 LayoutUnit gapExtra = (columnCount - 1) * colGap;
339 if (style().hasAutoColumnWidth())
340 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
341 else {
342 columnWidth = style().columnWidth();
343 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
344 }
345 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
346 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
347 // performing a layout pass, but this is not an appropriate time or place for layout. The
348 // good news is that if height is unconstrained and there are no explicit breaks, the
349 // resolved column-count really should be 1.
350 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
351 }
352}
353
354void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
355{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000356 if (childrenInline())
357 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
358 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000359 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
360
361 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
362
363 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
364
365 if (!style().autoWrap() && childrenInline()) {
366 // A horizontal marquee with inline children has no minimum width.
367 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
368 minLogicalWidth = 0;
369 }
370
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000371 if (is<RenderTableCell>(*this)) {
372 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000373 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
374 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
375 }
376
rego@igalia.com76760c72015-05-14 16:37:27 +0000377 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000378 maxLogicalWidth += scrollbarWidth;
379 minLogicalWidth += scrollbarWidth;
380}
381
382bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
383{
384 bool changed = recomputeLogicalWidth();
385
386 LayoutUnit oldColumnWidth = computedColumnWidth();
387 computeColumnCountAndWidth();
388
389 return changed || oldColumnWidth != computedColumnWidth();
390}
391
392LayoutUnit RenderBlockFlow::columnGap() const
393{
394 if (style().hasNormalColumnGap())
395 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
396 return style().columnGap();
397}
398
399void RenderBlockFlow::computeColumnCountAndWidth()
400{
401 // Calculate our column width and column count.
402 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
403 unsigned desiredColumnCount = 1;
404 LayoutUnit desiredColumnWidth = contentLogicalWidth();
405
406 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
407 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
408 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
409 return;
410 }
411
412 LayoutUnit availWidth = desiredColumnWidth;
413 LayoutUnit colGap = columnGap();
414 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
415 int colCount = std::max<int>(1, style().columnCount());
416
417 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
418 desiredColumnCount = colCount;
419 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
420 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
421 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
422 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
423 } else {
424 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
425 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
426 }
427 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
428}
429
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000430void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
431{
432 ASSERT(needsLayout());
433
434 if (!relayoutChildren && simplifiedLayout())
435 return;
436
437 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
438
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000439 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000440 relayoutChildren = true;
441
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000442 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000443
444 LayoutUnit previousHeight = logicalHeight();
445 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
446 // for consistency with other render classes?
447 setLogicalHeight(0);
448
449 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000450 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000451
akling@apple.com827be9c2013-10-29 02:58:43 +0000452 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000453 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000454
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000455 preparePaginationBeforeBlockLayout(relayoutChildren);
abucur@adobe.com0e81bc72013-10-22 14:50:37 +0000456 if (!relayoutChildren)
457 relayoutChildren = namedFlowFragmentNeedsUpdate();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000458
459 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
460 // our current maximal positive and negative margins. These values are used when we
461 // are collapsed with adjacent blocks, so for example, if you have block A and B
462 // collapsing together, then you'd take the maximal positive margin from both A and B
463 // and subtract it from the maximal negative margin from both A and B to get the
464 // true collapsed margin. This algorithm is recursive, so when we finish layout()
465 // our block knows its current maximal positive/negative values.
466 //
467 // Start out by setting our margin values to our current margins. Table cells have
468 // no margins, so we don't fill in the values for table cells.
469 bool isCell = isTableCell();
470 if (!isCell) {
471 initMaxMarginValues();
472
akling@apple.com827be9c2013-10-29 02:58:43 +0000473 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
474 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000475 setPaginationStrut(0);
476 }
477
478 LayoutUnit repaintLogicalTop = 0;
479 LayoutUnit repaintLogicalBottom = 0;
480 LayoutUnit maxFloatLogicalBottom = 0;
481 if (!firstChild() && !isAnonymousBlock())
482 setChildrenInline(true);
483 if (childrenInline())
484 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
485 else
486 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
487
488 // Expand our intrinsic height to encompass floats.
489 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000490 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000491 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
492
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000493 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000494 ASSERT(!shouldBreakAtLineToAvoidWidow());
495 return;
496 }
497
498 // Calculate our new height.
499 LayoutUnit oldHeight = logicalHeight();
500 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
501
502 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
503 // This ensures the size information is correctly computed for the last auto-height region receiving content.
cdumez@apple.com3abcc792014-10-20 03:42:03 +0000504 if (is<RenderFlowThread>(*this))
505 downcast<RenderFlowThread>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000506
507 updateLogicalHeight();
508 LayoutUnit newHeight = logicalHeight();
509 if (oldHeight != newHeight) {
510 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
511 // One of our children's floats may have become an overhanging float for us. We need to look for it.
akling@apple.com525dae62014-01-03 20:22:09 +0000512 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
513 if (blockFlow.isFloatingOrOutOfFlowPositioned())
514 continue;
515 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
516 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000517 }
518 }
519 }
520
521 bool heightChanged = (previousHeight != newHeight);
522 if (heightChanged)
523 relayoutChildren = true;
524
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000525 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000526
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000527 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
528 computeOverflow(oldClientAfterEdge);
529
530 statePusher.pop();
531
532 fitBorderToLinesIfNeeded();
533
534 if (view().layoutState()->m_pageLogicalHeight)
535 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
536
537 updateLayerTransform();
538
539 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
540 // we overflow or not.
541 updateScrollInfoAfterLayout();
542
543 // FIXME: This repaint logic should be moved into a separate helper function!
544 // Repaint with our new bounds if they are different from our old bounds.
545 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000546 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000547 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
548 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
549 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
550 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
551 if (hasOverflowClip()) {
552 // 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.
553 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
554 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000555 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
556 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000557 }
558
559 LayoutRect repaintRect;
560 if (isHorizontalWritingMode())
561 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
562 else
563 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
564
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000565 if (hasOverflowClip()) {
566 // Adjust repaint rect for scroll offset
567 repaintRect.move(-scrolledContentOffset());
568
569 // Don't allow this rect to spill out of our overflow box.
570 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
571 }
572
573 // Make sure the rect is still non-empty after intersecting for overflow above
574 if (!repaintRect.isEmpty()) {
575 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
576 if (hasReflection())
577 repaintRectangle(reflectedRect(repaintRect));
578 }
579 }
580
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000581 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000582}
583
584void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
585{
586 dirtyForLayoutFromPercentageHeightDescendants();
587
588 LayoutUnit beforeEdge = borderAndPaddingBefore();
589 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
590
591 setLogicalHeight(beforeEdge);
592
593 // Lay out our hypothetical grid line as though it occurs at the top of the block.
594 if (view().layoutState()->lineGrid() == this)
595 layoutLineGridBox();
596
597 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000598 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000599
600 // Fieldsets need to find their legend and position it inside the border of the object.
601 // The legend then gets skipped during normal layout. The same is true for ruby text.
602 // It doesn't get included in the normal layout process but is instead skipped.
603 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
604
605 LayoutUnit previousFloatLogicalBottom = 0;
606 maxFloatLogicalBottom = 0;
607
608 RenderBox* next = firstChildBox();
609
610 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000611 RenderBox& child = *next;
612 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000613
weinig@apple.com12840dc2013-10-22 23:59:08 +0000614 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000615 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
616
617 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
618
weinig@apple.com12840dc2013-10-22 23:59:08 +0000619 if (child.isOutOfFlowPositioned()) {
620 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000621 adjustPositionedBlock(child, marginInfo);
622 continue;
623 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000624 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000625 insertFloatingObject(child);
626 adjustFloatingBlock(marginInfo);
627 continue;
628 }
629
630 // Lay out the child.
631 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
632 }
633
634 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
635 // determining the correct collapsed bottom margin information.
636 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
637}
638
antti@apple.com940f5872013-10-24 20:31:11 +0000639void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
640{
akling@apple.coma12fee22015-02-01 02:58:13 +0000641 if (lineLayoutPath() == UndeterminedPath)
642 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000643
akling@apple.coma12fee22015-02-01 02:58:13 +0000644 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000645 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000646 return;
647 }
648
antti@apple.comfea51992013-10-28 13:39:23 +0000649 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000650 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
651}
652
weinig@apple.com12840dc2013-10-22 23:59:08 +0000653void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000654{
655 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
656 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
657
658 // The child is a normal flow object. Compute the margins we will use for collapsing now.
mmaxfield@apple.com09804f42016-03-23 00:58:34 +0000659 child.computeAndSetBlockDirectionMargins(*this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000660
661 // Try to guess our correct logical top position. In most cases this guess will
662 // be correct. Only if we're wrong (when we compute the real logical top position)
663 // will we have to potentially relayout.
664 LayoutUnit estimateWithoutPagination;
665 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
666
667 // 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 +0000668 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000669 LayoutUnit oldLogicalTop = logicalTopForChild(child);
670
671#if !ASSERT_DISABLED
672 LayoutSize oldLayoutDelta = view().layoutDelta();
673#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000674 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000675 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
676 estimateRegionRangeForBoxChild(child);
677
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000678 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000679 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000680 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000681 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000682 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
683 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
684 // very large elements. If it does the comparison with oldLogicalTop might yield a
685 // false negative as adding and removing margins, borders etc from a saturated number
686 // might yield incorrect results. If this is the case always mark for layout.
687 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000688 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000689 // If an element might be affected by the presence of floats, then always mark it for
690 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000691 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000692 if (fb > logicalTopEstimate)
693 markDescendantsWithFloats = true;
694 }
695
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000696 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000697 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000698 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000699 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000700 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000701 }
702
hyatt@apple.comccad3742015-02-04 21:39:00 +0000703 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000704
weinig@apple.com12840dc2013-10-22 23:59:08 +0000705 bool childHadLayout = child.everHadLayout();
706 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000707 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000708 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000709
710 // Cache if we are at the top of the block right now.
711 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
712
713 // Now determine the correct ypos based off examination of collapsing margin
714 // values.
715 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
716
717 // Now check for clear.
718 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
719
720 bool paginated = view().layoutState()->isPaginated();
721 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000722 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000723
724 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
725
726 // Now we have a final top position. See if it really does end up being different from our estimate.
727 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
728 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000729 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
730 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000731 // The child's width depends on the line width. When the child shifts to clear an item, its width can
732 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000733 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000734 }
735
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000736 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000737 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000738 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000739 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000740 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000741 }
742
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000743 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000744 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000745
746 // In case our guess was wrong, relayout the child.
747 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000748
749 // We are no longer at the top of the block if we encounter a non-empty child.
750 // 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 +0000751 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000752 marginInfo.setAtBeforeSideOfBlock(false);
753
754 // Now place the child in the correct left position
755 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
756
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000757 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000758 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000759 if (mustSeparateMarginAfterForChild(child)) {
760 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
761 marginInfo.clearMargin();
762 }
763 // If the child has overhanging floats that intrude into following siblings (or possibly out
764 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000765 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000766 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000767
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000768 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000769 if (childOffset.width() || childOffset.height()) {
770 view().addLayoutDelta(childOffset);
771
772 // If the child moved, we have to repaint it as well as any floating/positioned
773 // descendants. An exception is if we need a layout. In this case, we know we're going to
774 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000775 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
776 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000777 }
778
weinig@apple.com12840dc2013-10-22 23:59:08 +0000779 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
780 child.repaint();
781 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000782 }
783
784 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000785 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
786 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000787 // Check for an after page/column break.
788 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
789 if (newHeight != height())
790 setLogicalHeight(newHeight);
791 }
792
793 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
794}
795
weinig@apple.com12840dc2013-10-22 23:59:08 +0000796void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000797{
798 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000799 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000800
801 LayoutUnit logicalTop = logicalHeight();
zalan@apple.com4d97a002016-02-24 17:13:33 +0000802 updateStaticInlinePositionForChild(child, logicalTop, DoNotIndentText);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000803
804 if (!marginInfo.canCollapseWithMarginBefore()) {
805 // Positioned blocks don't collapse margins, so add the margin provided by
806 // the container now. The child's own margin is added later when calculating its logical top.
807 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
808 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
809 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
810 }
811
weinig@apple.com12840dc2013-10-22 23:59:08 +0000812 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000813 if (childLayer->staticBlockPosition() != logicalTop) {
814 childLayer->setStaticBlockPosition(logicalTop);
815 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000816 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000817 }
818}
819
robert@webkit.org97037ef2013-11-20 19:26:10 +0000820LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
821{
822 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000823 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000824 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
825 return marginValuesForChild(*this).positiveMarginBefore();
826 return LayoutUnit();
827}
828
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000829void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
830{
831 LayoutUnit startPosition = borderStart() + paddingStart();
mmaxfield@apple.com4195a702016-04-27 01:25:26 +0000832 if (shouldPlaceBlockDirectionScrollbarOnLeft())
mmaxfield@apple.comaf573be2016-03-12 21:18:25 +0000833 startPosition += (style().isLeftToRightDirection() ? 1 : -1) * verticalScrollbarWidth();
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000834 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
835
836 // Add in our start margin.
837 LayoutUnit childMarginStart = marginStartForChild(child);
838 LayoutUnit newPosition = startPosition + childMarginStart;
839
840 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
841 // to shift over as necessary to dodge any floats that might get in the way.
842 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
843 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
844
845 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
846}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000847
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000848void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
849{
850 // The float should be positioned taking into account the bottom margin
851 // of the previous flow. We add that margin into the height, get the
852 // float positioned properly, and then subtract the margin out of the
853 // height again. In the case of self-collapsing blocks, we always just
854 // use the top margins, since the self-collapsing block collapsed its
855 // own bottom margin into its top margin.
856 //
857 // Note also that the previous flow may collapse its margin into the top of
858 // our block. If this is the case, then we do not add the margin in to our
859 // height when computing the position of the float. This condition can be tested
860 // for by simply calling canCollapseWithMarginBefore. See
861 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
862 // an example of this scenario.
863 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
864 setLogicalHeight(logicalHeight() + marginOffset);
865 positionNewFloats();
866 setLogicalHeight(logicalHeight() - marginOffset);
867}
868
zalan@apple.com4d97a002016-02-24 17:13:33 +0000869void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000870{
akling@apple.com827be9c2013-10-29 02:58:43 +0000871 if (child.style().isOriginalDisplayInlineType())
zalan@apple.com4d97a002016-02-24 17:13:33 +0000872 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, shouldIndentText));
weinig@apple.com12840dc2013-10-22 23:59:08 +0000873 else
874 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
875}
876
877void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
878{
879 if (flowThreadContainingBlock()) {
880 // Shift the inline position to exclude the region offset.
881 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
882 }
883 child.layer()->setStaticInlinePosition(inlinePosition);
884}
885
886RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000887{
888 LayoutUnit childBeforePositive = 0;
889 LayoutUnit childBeforeNegative = 0;
890 LayoutUnit childAfterPositive = 0;
891 LayoutUnit childAfterNegative = 0;
892
893 LayoutUnit beforeMargin = 0;
894 LayoutUnit afterMargin = 0;
895
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000896 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000897
898 // If the child has the same directionality as we do, then we can just return its
899 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000900 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000901 if (childRenderBlock) {
902 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
903 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
904 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
905 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
906 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000907 beforeMargin = child.marginBefore();
908 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000909 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000910 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000911 // The child has a different directionality. If the child is parallel, then it's just
912 // flipped relative to us. We can use the margins for the opposite edges.
913 if (childRenderBlock) {
914 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
915 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
916 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
917 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
918 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000919 beforeMargin = child.marginAfter();
920 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000921 }
922 } else {
923 // The child is perpendicular to us, which means its margins don't collapse but are on the
924 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
925 beforeMargin = marginBeforeForChild(child);
926 afterMargin = marginAfterForChild(child);
927 }
928
929 // Resolve uncollapsing margins into their positive/negative buckets.
930 if (beforeMargin) {
931 if (beforeMargin > 0)
932 childBeforePositive = beforeMargin;
933 else
934 childBeforeNegative = -beforeMargin;
935 }
936 if (afterMargin) {
937 if (afterMargin > 0)
938 childAfterPositive = afterMargin;
939 else
940 childAfterNegative = -afterMargin;
941 }
942
943 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
944}
945
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000946bool RenderBlockFlow::childrenPreventSelfCollapsing() const
947{
948 if (!childrenInline())
949 return RenderBlock::childrenPreventSelfCollapsing();
950
951 // If the block has inline children, see if we generated any line boxes. If we have any
952 // line boxes, then we can only be self-collapsing if we have nothing but anonymous inline blocks
953 // that are also self-collapsing inside us.
954 if (!hasLines())
955 return false;
956
957 if (simpleLineLayout())
958 return true; // We have simple line layout lines, so we can't be self-collapsing.
959
960 for (auto* child = firstRootBox(); child; child = child->nextRootBox()) {
961 if (!child->hasAnonymousInlineBlock() || !child->anonymousInlineBlock()->isSelfCollapsingBlock())
962 return true;
963 }
964 return false; // We have no line boxes, so we must be self-collapsing.
965}
966
weinig@apple.com12840dc2013-10-22 23:59:08 +0000967LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000968{
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000969 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
970}
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000971
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000972LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
973{
974 bool childDiscardMarginBefore = child ? mustDiscardMarginBeforeForChild(*child) : false;
975 bool childDiscardMarginAfter = child ? mustDiscardMarginAfterForChild(*child) : false;
976 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
977 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
978 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
979
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000980 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
981 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000982
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000983 // Get the four margin values for the child and cache them.
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000984 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000985
986 // Get our max pos and neg top margins.
987 LayoutUnit posTop = childMargins.positiveMarginBefore();
988 LayoutUnit negTop = childMargins.negativeMarginBefore();
989
990 // For self-collapsing blocks, collapse our bottom margins into our
991 // top to get new posTop and negTop values.
992 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000993 posTop = std::max(posTop, childMargins.positiveMarginAfter());
994 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000995 }
996
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000997 if (marginInfo.canCollapseWithMarginBefore()) {
998 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
999 // This child is collapsing with the top of the
1000 // block. If it has larger margin values, then we need to update
1001 // our own maximal values.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001002 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +00001003 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001004
1005 // The minute any of the margins involved isn't a quirk, don't
1006 // collapse it away, even if the margin is smaller (www.webreference.com
1007 // has an example of this, a <dt> with 0.8em author-specified inside
1008 // a <dl> inside a <td>.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001009 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001010 setHasMarginBeforeQuirk(false);
1011 marginInfo.setDeterminedMarginBeforeQuirk(true);
1012 }
1013
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001014 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001015 // We have no top margin and our top child has a quirky margin.
1016 // We will pick up this quirky margin and pass it through.
1017 // This deals with the <td><div><p> case.
1018 // Don't do this for a block that split two inlines though. You do
1019 // still apply margins in this case.
1020 setHasMarginBeforeQuirk(true);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001021 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001022 } else
1023 // The before margin of the container will also discard all the margins it is collapsing with.
1024 setMustDiscardMarginBefore();
1025 }
1026
1027 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1028 if (childDiscardMarginBefore) {
1029 marginInfo.setDiscardMargin(true);
1030 marginInfo.clearMargin();
1031 }
1032
1033 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001034 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001035
1036 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1037 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001038
1039 LayoutUnit clearanceForSelfCollapsingBlock;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001040
robert@webkit.org97037ef2013-11-20 19:26:10 +00001041 // 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
1042 // 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
1043 // 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 +00001044 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1045 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001046 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1047 }
1048
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001049 if (childIsSelfCollapsing) {
1050 // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
1051 // Also, the child's top position equals the logical height of the container.
1052 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1053 // This child has no height. We need to compute our
1054 // position before we collapse the child's margins together,
1055 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001056 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1057 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001058 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1059
1060 // Now collapse the child's margins together, which means examining our
1061 // bottom margin values as well.
1062 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1063 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1064
1065 if (!marginInfo.canCollapseWithMarginBefore())
1066 // We need to make sure that the position of the self-collapsing block
1067 // is correct, since it could have overflowing content
1068 // that needs to be positioned correctly (e.g., a block that
1069 // had a specified height of 0 but that actually had subcontent).
1070 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1071 }
1072 } else {
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001073 if (child && mustSeparateMarginBeforeForChild(*child)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001074 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1075 // If we are at the before side of the block and we collapse, ignore the computed margin
1076 // and just add the child margin to the container height. This will correctly position
1077 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001078 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001079 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(*child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001080 logicalTop = logicalHeight();
1081 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1082 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1083 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1084 // We're collapsing with a previous sibling's margins and not
1085 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001086 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001087 logicalTop = logicalHeight();
1088 }
1089
1090 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1091
1092 if (!marginInfo.discardMargin()) {
1093 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1094 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1095 } else
1096 marginInfo.clearMargin();
1097
1098 if (marginInfo.margin())
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001099 marginInfo.setHasMarginAfterQuirk(afterQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001100 }
1101
1102 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1103 // collapsed into the page edge.
1104 LayoutState* layoutState = view().layoutState();
1105 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1106 && hasNextPage(beforeCollapseLogicalTop)) {
1107 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001108 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001109 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1110 }
1111
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001112 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001113 // 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
1114 // any floats from the parent will now overhang.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001115 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001116 LayoutUnit oldLogicalHeight = logicalHeight();
1117 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001118 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001119 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001120 setLogicalHeight(oldLogicalHeight);
1121
1122 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1123 // 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
1124 // floats in the parent that overhang |child|'s new logical top.
1125 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001126 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1127 child->setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001128 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001129
1130 return logicalTop;
1131}
1132
weinig@apple.com12840dc2013-10-22 23:59:08 +00001133LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001134{
1135 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1136 if (!heightIncrease)
1137 return yPos;
1138
weinig@apple.com12840dc2013-10-22 23:59:08 +00001139 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001140 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1141
1142 // For self-collapsing blocks that clear, they can still collapse their
1143 // margins with following siblings. Reset the current margins to represent
1144 // the self-collapsing block's margins only.
1145 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001146 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001147 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001148 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1149 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001150 } else
1151 marginInfo.clearMargin();
1152 marginInfo.setDiscardMargin(childDiscardMargin);
1153
1154 // CSS2.1 states:
1155 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1156 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1157 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1158 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1159 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001160 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001161 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1162 wouldCollapseMarginsWithParent = false;
1163 }
1164 if (wouldCollapseMarginsWithParent)
1165 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1166
robert@webkit.org97037ef2013-11-20 19:26:10 +00001167 // 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
1168 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1169 // 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
1170 // margins can collapse at the correct vertical position.
1171 // 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
1172 // (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],
1173 // i.e., clearance = [height of float] - margin-top".
1174 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001175 } else
1176 // Increase our height by the amount we had to clear.
1177 setLogicalHeight(logicalHeight() + heightIncrease);
1178
1179 if (marginInfo.canCollapseWithMarginBefore()) {
1180 // We can no longer collapse with the top of the block since a clear
1181 // occurred. The empty blocks collapse into the cleared block.
1182 // FIXME: This isn't quite correct. Need clarification for what to do
1183 // if the height the cleared block is offset by is smaller than the
1184 // margins involved.
1185 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1186 marginInfo.setAtBeforeSideOfBlock(false);
1187
1188 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
akling@apple.com827be9c2013-10-29 02:58:43 +00001189 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001190 }
1191
robert@webkit.org97037ef2013-11-20 19:26:10 +00001192 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001193}
1194
weinig@apple.com12840dc2013-10-22 23:59:08 +00001195void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001196{
1197 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1198 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1199 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001200 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001201 return;
1202
1203 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1204 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001205 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001206 positiveMarginBefore = 0;
1207 negativeMarginBefore = 0;
1208 discardMarginBefore = true;
1209 return;
1210 }
1211
1212 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001213 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1214 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001215
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001216 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001217 return;
1218
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001219 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001220 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001221 return;
1222
weinig@apple.com12840dc2013-10-22 23:59:08 +00001223 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001224 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1225 return;
1226
weinig@apple.com12840dc2013-10-22 23:59:08 +00001227 RenderBox* grandchildBox = childBlock.firstChildBox();
1228 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001229 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1230 break;
1231 }
1232
1233 // Give up if there is clearance on the box, since it probably won't collapse into us.
akling@apple.com827be9c2013-10-29 02:58:43 +00001234 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001235 return;
1236
1237 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1238 if (grandchildBox->needsLayout()) {
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00001239 grandchildBox->computeAndSetBlockDirectionMargins(*this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001240 if (is<RenderBlock>(*grandchildBox)) {
1241 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1242 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1243 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001244 }
1245 }
1246
1247 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001248 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001249}
1250
weinig@apple.com12840dc2013-10-22 23:59:08 +00001251LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001252{
1253 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1254 // relayout if there are intruding floats.
1255 LayoutUnit logicalTopEstimate = logicalHeight();
1256 if (!marginInfo.canCollapseWithMarginBefore()) {
1257 LayoutUnit positiveMarginBefore = 0;
1258 LayoutUnit negativeMarginBefore = 0;
1259 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001260 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001261 // Try to do a basic estimation of how the collapse is going to go.
1262 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1263 } else {
1264 // Use the cached collapsed margin values from a previous layout. Most of the time they
1265 // will be right.
1266 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001267 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1268 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001269 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1270 }
1271
1272 // Collapse the result with our current margins.
1273 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001274 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001275 }
1276
1277 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1278 // page.
1279 LayoutState* layoutState = view().layoutState();
1280 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1281 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001282 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001283
1284 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1285
1286 estimateWithoutPagination = logicalTopEstimate;
1287
1288 if (layoutState->isPaginated()) {
1289 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1290 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1291
1292 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1293 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1294
cdumez@apple.come9437792014-10-08 23:33:43 +00001295 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1296 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001297 }
1298
1299 return logicalTopEstimate;
1300}
1301
1302void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1303{
1304 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1305 // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
1306 // Don't update the max margin values because we won't need them anyway.
1307 if (marginInfo.discardMargin()) {
1308 setMustDiscardMarginAfter();
1309 return;
1310 }
1311
1312 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1313 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001314 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001315
1316 if (!marginInfo.hasMarginAfterQuirk())
1317 setHasMarginAfterQuirk(false);
1318
1319 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1320 // We have no bottom margin and our last child has a quirky margin.
1321 // We will pick up this quirky margin and pass it through.
1322 // This deals with the <td><div><p> case.
1323 setHasMarginAfterQuirk(true);
1324 }
1325}
1326
1327void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1328{
1329 marginInfo.setAtAfterSideOfBlock(true);
1330
robert@webkit.org97037ef2013-11-20 19:26:10 +00001331 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1332 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1333 // to perform now is at the child's margin-top - so adjust our height to that position.
1334 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001335 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1336 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001337
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001338 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001339 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1340 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1341 setLogicalHeight(logicalHeight() + marginInfo.margin());
1342
1343 // Now add in our bottom border/padding.
1344 setLogicalHeight(logicalHeight() + afterSide);
1345
1346 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1347 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001348 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001349
1350 // Update our bottom collapsed margin info.
1351 setCollapsedBottomMargin(marginInfo);
1352}
1353
1354void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1355{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001356 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001357 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001358 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001359 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001360 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001361
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001362 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1363 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001364}
1365
1366void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1367{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001368 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001369 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001370 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001371 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001372 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001373
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001374 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1375 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001376}
1377
1378void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1379{
akling@apple.com827be9c2013-10-29 02:58:43 +00001380 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001381 ASSERT(value);
1382 return;
1383 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001384
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001385 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001386 if (!value)
1387 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001388 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001389 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001390
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001391 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001392}
1393
1394void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1395{
akling@apple.com827be9c2013-10-29 02:58:43 +00001396 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001397 ASSERT(value);
1398 return;
1399 }
1400
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001401 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001402 if (!value)
1403 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001404 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001405 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001406
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001407 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001408}
1409
1410bool RenderBlockFlow::mustDiscardMarginBefore() const
1411{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001412 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001413}
1414
1415bool RenderBlockFlow::mustDiscardMarginAfter() const
1416{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001417 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001418}
1419
weinig@apple.com12840dc2013-10-22 23:59:08 +00001420bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001421{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001422 ASSERT(!child.selfNeedsLayout());
1423 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001424 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001425 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001426 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001427
1428 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1429 // In case the boxes are perpendicular we assume the property is not specified.
1430 return false;
1431}
1432
weinig@apple.com12840dc2013-10-22 23:59:08 +00001433bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001434{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001435 ASSERT(!child.selfNeedsLayout());
1436 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001437 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001438 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001439 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001440
1441 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1442 return false;
1443}
1444
weinig@apple.com12840dc2013-10-22 23:59:08 +00001445bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001446{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001447 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001448 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001449 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001450 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001451 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001452 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001453
1454 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1455 return false;
1456}
1457
weinig@apple.com12840dc2013-10-22 23:59:08 +00001458bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001459{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001460 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001461 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001462 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001463 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001464 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001465 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001466
1467 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1468 return false;
1469}
1470
weinig@apple.com12840dc2013-10-22 23:59:08 +00001471static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001472{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001473 RenderBlock* curr = child.containingBlock();
1474 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001475 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001476 return true;
1477 if (curr->isFloatingOrOutOfFlowPositioned())
1478 return false;
1479 curr = curr->containingBlock();
1480 }
1481 return true;
1482}
1483
weinig@apple.com12840dc2013-10-22 23:59:08 +00001484LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001485{
1486 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001487 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001488 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001489 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001490 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001491 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001492 bool checkBeforeAlways = (checkColumnBreaks && child.style().breakBefore() == ColumnBreakBetween)
1493 || (checkPageBreaks && alwaysPageBreak(child.style().breakBefore()))
1494 || (checkRegionBreaks && child.style().breakBefore() == RegionBreakBetween);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001495 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001496 if (checkColumnBreaks) {
1497 if (isInsideMulticolFlowThread)
1498 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001499 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001500 if (checkRegionBreaks) {
1501 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001502 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001503 return logicalOffset + offsetBreakAdjustment;
1504 }
1505 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1506 }
1507 return logicalOffset;
1508}
1509
weinig@apple.com12840dc2013-10-22 23:59:08 +00001510LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001511{
1512 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001513 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001514 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001515 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001516 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001517 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001518 bool checkAfterAlways = (checkColumnBreaks && child.style().breakAfter() == ColumnBreakBetween)
1519 || (checkPageBreaks && alwaysPageBreak(child.style().breakAfter()))
1520 || (checkRegionBreaks && child.style().breakAfter() == RegionBreakBetween);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001521 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1522 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1523
1524 // So our margin doesn't participate in the next collapsing steps.
1525 marginInfo.clearMargin();
1526
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001527 if (checkColumnBreaks) {
1528 if (isInsideMulticolFlowThread)
1529 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001530 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001531 if (checkRegionBreaks) {
1532 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001533 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001534 return logicalOffset + marginOffset + offsetBreakAdjustment;
1535 }
1536 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1537 }
1538 return logicalOffset;
1539}
1540
weinig@apple.com12840dc2013-10-22 23:59:08 +00001541LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001542{
cdumez@apple.come9437792014-10-08 23:33:43 +00001543 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001544
1545 if (estimateWithoutPagination != logicalTopAfterClear) {
1546 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1547 // position.
1548 setLogicalHeight(logicalTopAfterClear);
1549 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1550
weinig@apple.com12840dc2013-10-22 23:59:08 +00001551 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001552 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1553 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001554 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001555 }
1556
1557 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001558 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001559 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001560 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001561 }
1562
1563 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001564 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001565 }
1566
1567 LayoutUnit oldTop = logicalTopAfterClear;
1568
1569 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1570 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1571
1572 if (pageLogicalHeightForOffset(result)) {
1573 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001574 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001575 if (spaceShortage > 0) {
1576 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1577 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1578 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1579 // This should be improved, though, because here we just pretend that the child is
1580 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1581 // where there's no child content, border or padding. In other words, we risk stretching more
1582 // than necessary.
1583 setPageBreak(result, spaceShortage);
1584 }
1585 }
1586
1587 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1588 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1589 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1590
1591 LayoutUnit paginationStrut = 0;
1592 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1593 if (unsplittableAdjustmentDelta)
1594 paginationStrut = unsplittableAdjustmentDelta;
1595 else if (childRenderBlock && childRenderBlock->paginationStrut())
1596 paginationStrut = childRenderBlock->paginationStrut();
1597
1598 if (paginationStrut) {
1599 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1600 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1601 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1602 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1603 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1604 // and pushes to the next page anyway, so not too concerned about it.
1605 setPaginationStrut(result + paginationStrut);
1606 if (childRenderBlock)
1607 childRenderBlock->setPaginationStrut(0);
1608 } else
1609 result += paginationStrut;
1610 }
1611
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001612 // 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 +00001613 setLogicalHeight(logicalHeight() + (result - oldTop));
1614
1615 // Return the final adjusted logical top.
1616 return result;
1617}
1618
antti@apple.com5c4302b2016-04-26 18:20:09 +00001619static inline LayoutUnit calculateMinimumPageHeight(const RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001620{
1621 // We may require a certain minimum number of lines per page in order to satisfy
1622 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001623 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001624 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001625 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001626 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1627 line = line->prevRootBox();
1628
1629 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1630 // adjustLinePositionForPagination() for more details.
1631 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001632 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001633 }
1634 return lineBottom - lineTop;
1635}
1636
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001637static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1638{
bfulgham@apple.com62729772015-04-29 02:26:07 +00001639 const auto& renderer = lineBox.renderer();
1640
1641 if (!renderer.document().settings())
1642 return false;
1643
1644 if (!renderer.document().settings()->appleMailPaginationQuirkEnabled())
1645 return false;
1646
cdumez@apple.combee81ac2016-04-21 23:28:48 +00001647 if (renderer.element() && renderer.element()->idForStyleResolution() == "messageContentContainer")
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001648 return true;
1649
1650 return false;
1651}
1652
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001653void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001654{
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001655 // FIXME: Ignore anonymous inline blocks. Handle the delta already having been set because of
1656 // collapsing margins from a previous anonymous inline block.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001657 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1658 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1659 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1660 // of the first column.
1661 //
1662 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1663 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1664 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1665 // for overflow to occur), and then cache visible overflow for each column rect.
1666 //
1667 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1668 // content that paints in a previous column (and content that paints in the following column).
1669 //
1670 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1671 // at least make positive leading work in typical cases.
1672 //
1673 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1674 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1675 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001676 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001677 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001678 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1679 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001680 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001681 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001682 logicalOffset += delta;
1683 lineBox->setPaginationStrut(0);
1684 lineBox->setIsFirstAfterPageBreak(false);
1685 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1686 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1687 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1688 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001689 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001690 // 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.
1691 // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001692 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001693 }
1694
1695 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1696 // 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
1697 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1698 // 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
1699 // top of the page.
1700 // 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
1701 // this will be a real-world issue. For now we don't try to deal with this problem.
1702 logicalOffset = intMaxForLayoutUnit;
1703 logicalBottom = intMinForLayoutUnit;
1704 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1705 lineHeight = logicalBottom - logicalOffset;
1706 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1707 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1708 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1709 }
1710
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001711 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001712 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001713
1714 int lineIndex = lineCount(lineBox);
1715 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001716 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001717 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001718 setDidBreakAtLineToAvoidWidow();
1719 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001720 // If we have a non-uniform page height, then we have to shift further possibly.
1721 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1722 return;
1723 if (lineHeight > pageLogicalHeight) {
1724 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001725 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001726 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001727 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1728 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001729 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001730 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1731 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001732 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001733 && !isOutOfFlowPositioned() && !isTableCell()) {
1734 auto firstRootBox = this->firstRootBox();
1735 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1736 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001737 if (needsAppleMailPaginationQuirk(*lineBox))
1738 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001739 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1740 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001741 delta += remainingLogicalHeight;
1742 lineBox->setPaginationStrut(remainingLogicalHeight);
1743 lineBox->setIsFirstAfterPageBreak(true);
1744 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001745 } else if (remainingLogicalHeight == pageLogicalHeight) {
1746 // We're at the very top of a page or column.
1747 if (lineBox != firstRootBox())
1748 lineBox->setIsFirstAfterPageBreak(true);
1749 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1750 setPageBreak(logicalOffset, lineHeight);
1751 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001752}
1753
1754void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1755{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001756 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001757 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1758 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001759}
1760
abucur@adobe.comfc497132013-10-04 08:49:21 +00001761void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1762{
1763 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001764 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001765 return;
1766
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001767 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001768}
1769
1770void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1771{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001772 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001773 return;
1774
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001775 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001776}
1777
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001778void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1779{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001780 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001781 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001782 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001783
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001784 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001785}
1786
1787bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1788{
1789 if (!shouldBreakAtLineToAvoidWidow())
1790 return false;
1791
1792 statePusher.pop();
1793 setEverHadLayout(true);
1794 layoutBlock(false);
1795 return true;
1796}
1797
weinig@apple.com31324fd2013-10-28 19:22:51 +00001798bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1799{
1800 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1801
1802 RenderFlowThread* flowThread = flowThreadContainingBlock();
1803 if (!flowThread)
1804 return true; // Printing and multi-column both make new pages to accommodate content.
1805
1806 // See if we're in the last region.
1807 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001808 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001809 if (!region)
1810 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001811
weinig@apple.com31324fd2013-10-28 19:22:51 +00001812 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001813 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001814 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001815
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001816 RenderRegion* startRegion = nullptr;
1817 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001818 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001819 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001820}
1821
1822LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1823{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001824 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001825 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001826
1827 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001828 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1829 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1830 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1831 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1832 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1833 || !hasNextPage(logicalOffset))
1834 return logicalOffset;
1835 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1836 if (remainingLogicalHeight < childLogicalHeight) {
1837 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1838 return logicalOffset;
1839 return logicalOffset + remainingLogicalHeight;
1840 }
1841 return logicalOffset;
1842}
1843
1844bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1845{
1846 bool checkRegion = false;
1847 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1848 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1849 if (minimumLogicalHeight <= pageLogicalHeight)
1850 return true;
1851 if (!hasNextPage(logicalOffset + adjustment))
1852 return false;
1853 adjustment += pageLogicalHeight;
1854 checkRegion = true;
1855 }
1856 return !checkRegion;
1857}
1858
1859void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1860{
1861 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1862 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1863}
1864
1865void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1866{
1867 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1868 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001869}
1870
1871LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1872{
1873 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1874 if (!pageLogicalHeight)
1875 return logicalOffset;
1876
1877 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1878 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1879 if (pageBoundaryRule == ExcludePageBoundary)
1880 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1881 return logicalOffset + remainingLogicalHeight;
1882}
1883
1884LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1885{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001886 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1887 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1888 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1889 if (!pageLogicalHeight)
1890 return 0;
1891
weinig@apple.com31324fd2013-10-28 19:22:51 +00001892 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1893 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1894
1895 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1896 RenderFlowThread* flowThread = flowThreadContainingBlock();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001897 if (!flowThread)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001898 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001899 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001900}
1901
1902LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1903{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001904 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1905 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1906 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1907 if (!pageLogicalHeight)
1908 return 0;
1909
1910 // Now check for a flow thread.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001911 RenderFlowThread* flowThread = flowThreadContainingBlock();
1912 if (!flowThread)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001913 return pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001914 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1915}
1916
1917LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1918{
1919 offset += offsetFromLogicalTopOfFirstPage();
1920
1921 RenderFlowThread* flowThread = flowThreadContainingBlock();
1922 if (!flowThread) {
1923 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1924 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1925 if (pageBoundaryRule == IncludePageBoundary) {
1926 // If includeBoundaryPoint is true the line exactly on the top edge of a
1927 // column will act as being part of the previous column.
1928 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1929 }
1930 return remainingHeight;
1931 }
1932
1933 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1934}
1935
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001936LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1937{
1938 // This method is required because regions do not fragment monolithic elements but instead
1939 // they let them overflow the region they flow in. This behaviour is different from the
1940 // multicol/printing implementations, which have not yet been updated to correctly handle
1941 // monolithic elements.
1942 // As a result, for the moment, this method will only be used for regions, the multicol and
1943 // printing implementations will stick to the existing behaviour until their fragmentation
1944 // implementation is updated to match the regions implementation.
1945 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1946 return logicalHeightForChild(child);
1947
1948 // For unsplittable elements, this method will just return the height of the element that
1949 // fits into the current region, without the height of the part that overflows the region.
1950 // This is done for all regions, except the last one because in that case, the logical
1951 // height of the flow thread needs to also
1952 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1953 return logicalHeightForChild(child);
1954
1955 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1956 // the entire unsplittable child because any following children will not be moved to the next page
1957 // so they will need to be laid out below the current unsplittable child.
1958 LayoutUnit childLogicalTop = logicalTopForChild(child);
1959 if (!hasNextPage(childLogicalTop))
1960 return logicalHeightForChild(child);
1961
1962 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1963 return std::min(child.logicalHeight(), remainingLogicalHeight);
1964}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001965
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001966void RenderBlockFlow::layoutLineGridBox()
1967{
akling@apple.com827be9c2013-10-29 02:58:43 +00001968 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001969 setLineGridBox(0);
1970 return;
1971 }
1972
1973 setLineGridBox(0);
1974
akling@apple.com1aa97b02013-10-31 21:59:49 +00001975 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001976 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1977 lineGridBox->setConstructed();
1978 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1979 VerticalPositionCache verticalPositionCache;
1980 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1981
aestes@apple.com13aae082016-01-02 08:03:08 +00001982 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001983
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001984 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1985 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1986 // to this grid.
1987}
1988
weinig@apple.com12840dc2013-10-22 23:59:08 +00001989bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001990{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001991 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001992}
1993
1994void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1995{
1996 RenderBlock::styleDidChange(diff, oldStyle);
1997
1998 // After our style changed, if we lose our ability to propagate floats into next sibling
1999 // blocks, then we need to find the top most parent containing that overhanging float and
2000 // then mark its descendants with floats for layout and clear all floats from its next
2001 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
2002 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
2003 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2004 RenderBlockFlow* parentBlock = this;
2005 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002006
weinig@apple.comc77041e2013-12-14 18:05:45 +00002007 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2008 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00002009 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00002010 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002011 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2012 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002013 if (ancestor.hasOverhangingFloat(renderer)) {
2014 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002015 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002016 }
2017 }
2018 }
2019 }
2020
2021 parentBlock->markAllDescendantsWithFloatsForLayout();
2022 parentBlock->markSiblingsWithFloatsForLayout();
2023 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002024
akling@apple.com8f40c5b2013-10-27 22:54:07 +00002025 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00002026 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00002027
antti@apple.com9e891c82014-05-22 06:12:34 +00002028 if (diff >= StyleDifferenceRepaint) {
2029 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2030 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2031 invalidateLineLayoutPath();
2032 }
2033
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002034 if (multiColumnFlowThread())
2035 updateStylesForColumnChildren();
2036}
2037
2038void RenderBlockFlow::updateStylesForColumnChildren()
2039{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002040 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
antti@apple.com454418f2016-04-25 19:49:23 +00002041 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002042}
2043
akling@apple.combdae43242013-10-25 12:00:20 +00002044void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002045{
akling@apple.com827be9c2013-10-29 02:58:43 +00002046 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002047 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2048
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002049 if (oldStyle) {
2050 EPosition oldPosition = oldStyle->position();
2051 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002052
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002053 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2054 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2055 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002056 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002057 }
2058
2059 RenderBlock::styleWillChange(diff, newStyle);
2060}
2061
antti@apple.coma2c7f242013-10-22 22:37:25 +00002062void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002063{
2064 if (containsFloats())
2065 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002066
antti@apple.comfea51992013-10-28 13:39:23 +00002067 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002068 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002069 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002070 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002071 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002072
antti@apple.coma2c7f242013-10-22 22:37:25 +00002073 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002074}
2075
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002076void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002077{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002078 // When a portion of the render tree is being detached, anonymous blocks
2079 // will be combined as their children are deleted. In this process, the
2080 // anonymous block later in the tree is merged into the one preceeding it.
2081 // It can happen that the later block (this) contains floats that the
2082 // previous block (toBlockFlow) did not contain, and thus are not in the
2083 // floating objects list for toBlockFlow. This can result in toBlockFlow
2084 // containing floats that are not in it's floating objects list, but are in
2085 // the floating objects lists of siblings and parents. This can cause
2086 // problems when the float itself is deleted, since the deletion code
2087 // assumes that if a float is not in it's containing block's floating
2088 // objects list, it isn't in any floating objects list. In order to
2089 // preserve this condition (removing it has serious performance
2090 // implications), we need to copy the floating objects from the old block
2091 // (this) to the new block (toBlockFlow). The float's metrics will likely
2092 // all be wrong, but since toBlockFlow is already marked for layout, this
2093 // will get fixed before anything gets displayed.
2094 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2095 if (m_floatingObjects) {
2096 if (!toBlockFlow->m_floatingObjects)
2097 toBlockFlow->createFloatingObjects();
2098
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002099 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2100 auto end = fromFloatingObjectSet.end();
2101
2102 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2103 FloatingObject* floatingObject = it->get();
2104
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002105 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002106 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002107 continue;
2108
2109 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2110 }
2111 }
2112}
2113
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002114void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002115{
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002116 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2117 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2118 moveFloatsTo(&toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002119}
2120
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002121void RenderBlockFlow::addOverflowFromFloats()
2122{
2123 if (!m_floatingObjects)
2124 return;
2125
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002126 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2127 auto end = floatingObjectSet.end();
2128 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002129 const auto& floatingObject = *it->get();
2130 if (floatingObject.isDescendant())
2131 addOverflowFromChild(&floatingObject.renderer(), IntSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002132 }
2133}
2134
2135void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2136{
2137 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2138
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002139 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002140 addOverflowFromFloats();
2141}
2142
2143void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2144{
2145 // Repaint any overhanging floats (if we know we're the one to paint them).
2146 // Otherwise, bail out.
2147 if (!hasOverhangingFloats())
2148 return;
2149
2150 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2151 // in this block. Better yet would be to push extra state for the containers of other floats.
zalan@apple.com163bc1c2015-08-12 03:41:40 +00002152 LayoutStateDisabler layoutStateDisabler(view());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002153 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2154 auto end = floatingObjectSet.end();
2155 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002156 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002157 // Only repaint the object if it is overhanging, is not in its own layer, and
2158 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2159 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002160 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002161 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002162 && !renderer.hasSelfPaintingLayer()
2163 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2164 renderer.repaint();
2165 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002166 }
2167 }
2168}
2169
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002170void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002171{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002172 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002173
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002174 if (!multiColumnFlowThread() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002175 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002176
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002177 // Iterate over our children and paint the column rules as needed.
2178 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2179 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2180 columnSet.paintColumnRules(paintInfo, childPoint);
2181 }
2182}
2183
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002184void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2185{
2186 if (!m_floatingObjects)
2187 return;
2188
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002189 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2190 auto end = floatingObjectSet.end();
2191 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002192 const auto& floatingObject = *it->get();
2193 auto& renderer = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002194 // Only paint the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002195 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002196 PaintInfo currentPaintInfo(paintInfo);
2197 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2198 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
zalan@apple.com6816b132015-10-17 19:14:53 +00002199 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject,
2200 LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(floatingObject) - renderer.x(),
2201 paintOffset.y() + yPositionForFloatIncludingMargin(floatingObject) - renderer.y()));
2202 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002203 if (!preservePhase) {
2204 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002205 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002206 currentPaintInfo.phase = PaintPhaseFloat;
zalan@apple.com6816b132015-10-17 19:14:53 +00002207 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002208 currentPaintInfo.phase = PaintPhaseForeground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002209 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002210 currentPaintInfo.phase = PaintPhaseOutline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002211 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002212 }
2213 }
2214 }
2215}
2216
weinig@apple.com12840dc2013-10-22 23:59:08 +00002217void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002218{
2219 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002220 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2221 auto end = floatingObjectSet.end();
2222 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002223 const auto& floatingObject = *it->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002224 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2225 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
zalan@apple.com6816b132015-10-17 19:14:53 +00002226 floatingObject.renderer().width(), floatingObject.renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002227 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002228 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002229 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002230 }
2231 }
2232}
2233
2234void RenderBlockFlow::createFloatingObjects()
2235{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002236 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002237}
2238
2239void RenderBlockFlow::removeFloatingObjects()
2240{
2241 if (!m_floatingObjects)
2242 return;
2243
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002244 markSiblingsWithFloatsForLayout();
2245
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002246 m_floatingObjects->clear();
2247}
2248
weinig@apple.com12840dc2013-10-22 23:59:08 +00002249FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002250{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002251 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002252
2253 // Create the list of special objects if we don't aleady have one
2254 if (!m_floatingObjects)
2255 createFloatingObjects();
2256 else {
2257 // Don't insert the floatingObject again if it's already in the list
2258 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002259 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002260 if (it != floatingObjectSet.end())
2261 return it->get();
2262 }
2263
2264 // Create the special floatingObject entry & append it to the list
2265
weinig@apple.com12840dc2013-10-22 23:59:08 +00002266 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002267
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002268 // 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 +00002269 bool isChildRenderBlock = floatBox.isRenderBlock();
2270 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2271 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002272
2273 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002274 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2275 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002276 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002277 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2278 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002279 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002280 floatBox.updateLogicalWidth();
mmaxfield@apple.com09804f42016-03-23 00:58:34 +00002281 floatBox.computeAndSetBlockDirectionMargins(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002282 }
2283
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002284 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002285
aestes@apple.com13aae082016-01-02 08:03:08 +00002286 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002287}
2288
weinig@apple.com12840dc2013-10-22 23:59:08 +00002289void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002290{
2291 if (m_floatingObjects) {
2292 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002293 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002294 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002295 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002296 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002297 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2298 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002299
2300 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2301 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2302 logicalBottom = LayoutUnit::max();
2303 else {
2304 // Special-case zero- and less-than-zero-height floats: those don't touch
2305 // the line that they're on, but it still needs to be dirtied. This is
2306 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002307 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002308 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002309 if (floatingObject.originatingLine()) {
2310 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002311 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002312 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2313 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002314 }
2315#if !ASSERT_DISABLED
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002316 floatingObject.setOriginatingLine(0);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002317#endif
2318 }
2319 markLinesDirtyInBlockRange(0, logicalBottom);
2320 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002321 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002322 }
2323 }
2324}
2325
2326void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2327{
2328 if (!containsFloats())
2329 return;
2330
2331 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2332 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002333 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002334 m_floatingObjects->remove(curr);
2335 if (floatingObjectSet.isEmpty())
2336 break;
2337 curr = floatingObjectSet.last().get();
2338 }
2339}
2340
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002341LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2342{
2343 LayoutUnit offset = fixedOffset;
2344 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2345 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2346 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2347}
2348
2349LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2350{
2351 LayoutUnit offset = fixedOffset;
2352 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2353 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2354 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2355}
2356
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002357LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject& floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002358{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002359 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002360 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002361 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002362
andersca@apple.com86298632013-11-10 19:32:33 +00002363 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002364
2365 LayoutUnit floatLogicalLeft;
2366
2367 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002368 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2369
2370 if (isInitialLetter) {
2371 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2372 if (letterClearance > 0) {
2373 logicalTopOffset += letterClearance;
2374 setLogicalHeight(logicalHeight() + letterClearance);
2375 }
2376 }
2377
akling@apple.com827be9c2013-10-29 02:58:43 +00002378 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002379 LayoutUnit heightRemainingLeft = 1;
2380 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002381 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2382 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002383 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002384 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002385 if (insideFlowThread) {
2386 // Have to re-evaluate all of our offsets, since they may have changed.
2387 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2388 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002389 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002390 }
2391 }
andersca@apple.com86298632013-11-10 19:32:33 +00002392 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002393 } else {
2394 LayoutUnit heightRemainingLeft = 1;
2395 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002396 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2397 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002398 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002399 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002400 if (insideFlowThread) {
2401 // Have to re-evaluate all of our offsets, since they may have changed.
2402 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2403 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002404 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002405 }
2406 }
2407 // Use the original width of the float here, since the local variable
2408 // |floatLogicalWidth| was capped to the available line width. See
2409 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002410 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002411 }
2412
hyatt@apple.com87515262014-09-04 21:20:12 +00002413 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002414 const RenderStyle& style = firstLineStyle();
2415 const FontMetrics& fontMetrics = style.fontMetrics();
2416 if (fontMetrics.hasCapHeight()) {
2417 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2418 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2419
2420 // Make an adjustment to align with the cap height of a theoretical block line.
2421 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2422 logicalTopOffset += adjustment;
2423
2424 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2425 // positive for raised and negative for sunken).
2426 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2427
2428 // 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.
2429 if (dropHeightDelta < 0) {
2430 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2431 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2432 }
2433
2434 // 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
2435 // empty lines beside the first letter.
2436 if (dropHeightDelta > 0)
2437 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2438 }
2439 }
2440
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002441 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2442}
2443
2444bool RenderBlockFlow::positionNewFloats()
2445{
2446 if (!m_floatingObjects)
2447 return false;
2448
2449 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2450 if (floatingObjectSet.isEmpty())
2451 return false;
2452
2453 // If all floats have already been positioned, then we have no work to do.
2454 if (floatingObjectSet.last()->isPlaced())
2455 return false;
2456
2457 // Move backwards through our floating object list until we find a float that has
2458 // already been positioned. Then we'll be able to move forward, positioning all of
2459 // the new floats that need it.
2460 auto it = floatingObjectSet.end();
2461 --it; // Go to last item.
2462 auto begin = floatingObjectSet.begin();
2463 FloatingObject* lastPlacedFloatingObject = 0;
2464 while (it != begin) {
2465 --it;
2466 if ((*it)->isPlaced()) {
2467 lastPlacedFloatingObject = it->get();
2468 ++it;
2469 break;
2470 }
2471 }
2472
2473 LayoutUnit logicalTop = logicalHeight();
2474
2475 // The float cannot start above the top position of the last positioned float.
2476 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002477 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002478
2479 auto end = floatingObjectSet.end();
2480 // Now walk through the set of unpositioned floats and place them.
2481 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002482 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002483 // The containing block is responsible for positioning floats, so if we have floats in our
2484 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002485 auto& childBox = floatingObject.renderer();
2486 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002487 continue;
2488
akling@apple.com827be9c2013-10-29 02:58:43 +00002489 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002490
weinig@apple.com12840dc2013-10-22 23:59:08 +00002491 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002492
akling@apple.com827be9c2013-10-29 02:58:43 +00002493 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002494 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002495 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002496 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002497
2498 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2499
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002500 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002501
2502 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2503 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2504
2505 estimateRegionRangeForBoxChild(childBox);
2506
hyatt@apple.comccad3742015-02-04 21:39:00 +00002507 childBox.markForPaginationRelayoutIfNeeded();
2508 childBox.layoutIfNeeded();
2509
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002510 LayoutState* layoutState = view().layoutState();
2511 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002512 if (isPaginated) {
2513 // If we are unsplittable and don't fit, then we need to move down.
2514 // We include our margins as part of the unsplittable area.
2515 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2516
2517 // See if we have a pagination strut that is making us move down further.
2518 // Note that an unsplittable child can't also have a pagination strut, so this is
2519 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002520 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002521 if (childBlock && childBlock->paginationStrut()) {
2522 newLogicalTop += childBlock->paginationStrut();
2523 childBlock->setPaginationStrut(0);
2524 }
2525
2526 if (newLogicalTop != floatLogicalLocation.y()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002527 floatingObject.setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002528
2529 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002530 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002531
2532 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2533 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2534
2535 if (childBlock)
2536 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002537 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002538 }
2539
2540 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002541 childBox.setNeedsLayout(MarkOnlyThis);
2542 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002543 }
2544 }
2545
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002546 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002547
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002548 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002549
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002550 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002551
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002552#if ENABLE(CSS_SHAPES)
2553 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002554 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002555#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002556 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002557 if (childBox.checkForRepaintDuringLayout())
2558 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002559 }
2560 return true;
2561}
2562
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002563void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002564{
2565 positionNewFloats();
2566 // set y position
2567 LayoutUnit newY = 0;
2568 switch (clear) {
2569 case CLEFT:
2570 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2571 break;
2572 case CRIGHT:
2573 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2574 break;
2575 case CBOTH:
2576 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002577 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002578 default:
2579 break;
2580 }
2581 if (height() < newY)
2582 setLogicalHeight(newY);
2583}
2584
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002585LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002586{
2587 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002588 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002589
2590 return fixedOffset;
2591}
2592
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002593LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002594{
2595 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002596 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002597
2598 return fixedOffset;
2599}
2600
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002601LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002602{
2603 if (!m_floatingObjects)
2604 return logicalHeight;
2605
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002606 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2607}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002608
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002609LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2610{
2611 if (!m_floatingObjects)
2612 return logicalHeight;
2613
2614 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002615}
2616
2617LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2618{
2619 if (!m_floatingObjects)
2620 return 0;
2621 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002622 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2623 auto end = floatingObjectSet.end();
2624 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002625 const auto& floatingObject = *it->get();
2626 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002627 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002628 }
2629 return lowestFloatBottom;
2630}
2631
hyatt@apple.com87515262014-09-04 21:20:12 +00002632LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2633{
2634 if (!m_floatingObjects)
2635 return 0;
2636 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002637 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2638 auto end = floatingObjectSet.end();
2639 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002640 const auto& floatingObject = *it->get();
2641 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == FIRST_LETTER && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002642 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002643 }
2644 return lowestFloatBottom;
2645}
2646
weinig@apple.com12840dc2013-10-22 23:59:08 +00002647LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002648{
2649 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002650 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002651 return 0;
2652
weinig@apple.com12840dc2013-10-22 23:59:08 +00002653 LayoutUnit childLogicalTop = child.logicalTop();
2654 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002655 LayoutUnit lowestFloatLogicalBottom = 0;
2656
2657 // Floats that will remain the child's responsibility to paint should factor into its
2658 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002659 auto childEnd = child.m_floatingObjects->set().end();
2660 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002661 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002662 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002663 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002664 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002665
2666 if (logicalBottom > logicalHeight()) {
2667 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002668 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002669 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2670 bool shouldPaint = false;
2671
2672 // The nearest enclosing layer always paints the float (so that zindex and stacking
2673 // behaves properly). We always want to propagate the desire to paint the float as
2674 // far out as we can, to the outermost block that overlaps the float, stopping only
2675 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002676 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2677 floatingObject.setShouldPaint(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002678 shouldPaint = true;
2679 }
2680 // We create the floating object list lazily.
2681 if (!m_floatingObjects)
2682 createFloatingObjects();
2683
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002684 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002685 }
2686 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002687 const auto& renderer = floatingObject.renderer();
2688 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2689 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002690 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2691 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2692 // layer.
2693 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2694 // it should paint.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002695 floatingObject.setShouldPaint(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002696 }
2697
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002698 // 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 +00002699 if (floatingObject.isDescendant())
zalan@apple.com6816b132015-10-17 19:14:53 +00002700 child.addOverflowFromChild(&renderer, LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002701 }
2702 }
2703 return lowestFloatLogicalBottom;
2704}
2705
weinig@apple.com12840dc2013-10-22 23:59:08 +00002706bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002707{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002708 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002709 return false;
2710
2711 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002712 const auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002713 if (it == floatingObjectSet.end())
2714 return false;
2715
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002716 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002717}
2718
hyatt@apple.com21c60802015-04-01 18:10:32 +00002719void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002720{
2721 ASSERT(!avoidsFloats());
2722
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002723 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2724 if (createsNewFormattingContext())
2725 return;
2726
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002727 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2728 if (!prev->m_floatingObjects)
2729 return;
2730
2731 logicalLeftOffset += marginLogicalLeft();
2732
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002733 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2734 auto prevEnd = prevSet.end();
2735 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002736 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002737 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002738 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002739 // We create the floating object list lazily.
2740 if (!m_floatingObjects)
2741 createFloatingObjects();
2742
2743 // Applying the child's margin makes no sense in the case where the child was passed in.
2744 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2745 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2746 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2747 // will get applied twice.
2748 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002749 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2750 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002751
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002752 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002753 }
2754 }
2755 }
2756}
2757
2758void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2759{
2760 if (!everHadLayout() && !containsFloats())
2761 return;
2762
2763 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2764 setChildNeedsLayout(markParents);
2765
2766 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002767 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002768
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002769 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002770 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2771 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2772 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002773 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002774 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2775 block.setChildNeedsLayout(markParents);
2776 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002777 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002778 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002779 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2780 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002781 }
2782}
2783
2784void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2785{
2786 if (!m_floatingObjects)
2787 return;
2788
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002789 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2790 auto end = floatingObjectSet.end();
2791
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002792 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002793 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002794 continue;
2795
cdumez@apple.come9437792014-10-08 23:33:43 +00002796 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002797 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2798 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002799 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002800 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002801 if (nextBlock.containsFloat(floatingBox))
2802 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002803 }
2804 }
2805}
2806
zalan@apple.com6816b132015-10-17 19:14:53 +00002807LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002808{
akling@apple.com827be9c2013-10-29 02:58:43 +00002809 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002810 return point;
2811
2812 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2813 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2814 // case.
2815 if (isHorizontalWritingMode())
zalan@apple.com6816b132015-10-17 19:14:53 +00002816 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2817 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002818}
2819
weinig@apple.com12840dc2013-10-22 23:59:08 +00002820LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002821{
2822 // There is no need to compute clearance if we have no floats.
2823 if (!containsFloats())
2824 return 0;
2825
2826 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002827 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002828 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002829 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002830 case CNONE:
2831 break;
2832 case CLEFT:
2833 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2834 break;
2835 case CRIGHT:
2836 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2837 break;
2838 case CBOTH:
2839 logicalBottom = lowestFloatLogicalBottom();
2840 break;
2841 }
2842
2843 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
andersca@apple.com86298632013-11-10 19:32:33 +00002844 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002845 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002846 LayoutUnit newLogicalTop = logicalTop;
2847 while (true) {
zalan@apple.com64761fe2016-03-02 21:42:22 +00002848 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002849 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2850 return newLogicalTop - logicalTop;
2851
2852 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002853 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002854 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2855
2856 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002857 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2858 LayoutUnit childOldMarginLeft = child.marginLeft();
2859 LayoutUnit childOldMarginRight = child.marginRight();
2860 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002861
weinig@apple.com12840dc2013-10-22 23:59:08 +00002862 child.setLogicalTop(newLogicalTop);
2863 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002864 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002865 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002866 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2867
weinig@apple.com12840dc2013-10-22 23:59:08 +00002868 child.setLogicalTop(childOldLogicalTop);
2869 child.setLogicalWidth(childOldLogicalWidth);
2870 child.setMarginLeft(childOldMarginLeft);
2871 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002872
2873 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2874 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2875 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2876 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2877 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002878 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002879 return newLogicalTop - logicalTop;
2880 }
2881
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002882 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002883 ASSERT(newLogicalTop >= logicalTop);
2884 if (newLogicalTop < logicalTop)
2885 break;
2886 }
2887 ASSERT_NOT_REACHED();
2888 }
2889 return result;
2890}
2891
2892bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2893{
2894 if (!m_floatingObjects)
2895 return false;
2896
2897 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002898 if (is<RenderView>(*this))
2899 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002900
2901 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2902 auto begin = floatingObjectSet.begin();
2903 for (auto it = floatingObjectSet.end(); it != begin;) {
2904 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002905 const auto& floatingObject = *it->get();
2906 auto& renderer = floatingObject.renderer();
2907 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
2908 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - renderer.x();
2909 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - renderer.y();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002910 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
zalan@apple.com6816b132015-10-17 19:14:53 +00002911 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002912 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2913 return true;
2914 }
2915 }
2916 }
2917
2918 return false;
2919}
2920
weinig@apple.com611b9292013-10-20 22:57:54 +00002921bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2922{
2923 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002924
darin@apple.come1be6ca2014-04-28 04:19:10 +00002925 if (auto simpleLineLayout = this->simpleLineLayout())
2926 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002927
weinig@apple.com611b9292013-10-20 22:57:54 +00002928 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2929}
2930
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002931void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2932{
akling@apple.com827be9c2013-10-29 02:58:43 +00002933 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002934 return;
2935
2936 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2937 // for either overflow or translations via relative positioning.
2938 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002939 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2940
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002941 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002942 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002943 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002944 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002945 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002946 }
2947 } else {
2948 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2949 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002950 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2951 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002952 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002953 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002954 left = std::min(left, x + obj->x());
2955 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002956 }
2957 }
2958 }
2959 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002960
2961 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002962 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2963 auto end = floatingObjectSet.end();
2964 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002965 const auto& floatingObject = *it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002966 // Only examine the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002967 if (floatingObject.shouldPaint()) {
2968 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(floatingObject) - floatingObject.renderer().x();
2969 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002970 left = std::min(left, floatLeft);
2971 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002972 }
2973 }
2974 }
2975}
2976
2977void RenderBlockFlow::fitBorderToLinesIfNeeded()
2978{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002979 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002980 return;
2981
2982 // Walk any normal flow lines to snugly fit.
2983 LayoutUnit left = LayoutUnit::max();
2984 LayoutUnit right = LayoutUnit::min();
2985 LayoutUnit oldWidth = contentWidth();
2986 adjustForBorderFit(0, left, right);
2987
2988 // Clamp to our existing edges. We can never grow. We only shrink.
2989 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2990 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002991 left = std::min(rightEdge, std::max(leftEdge, left));
2992 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002993
2994 LayoutUnit newContentWidth = right - left;
2995 if (newContentWidth == oldWidth)
2996 return;
2997
2998 setOverrideLogicalContentWidth(newContentWidth);
2999 layoutBlock(false);
3000 clearOverrideLogicalContentWidth();
3001}
3002
3003void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3004{
3005 if (logicalTop >= logicalBottom)
3006 return;
3007
antti@apple.combe9d3e12014-05-11 09:42:47 +00003008 // Floats currently affect the choice whether to use simple line layout path.
3009 if (m_simpleLineLayout) {
3010 invalidateLineLayoutPath();
3011 return;
3012 }
3013
weinig@apple.com611b9292013-10-20 22:57:54 +00003014 RootInlineBox* lowestDirtyLine = lastRootBox();
3015 RootInlineBox* afterLowest = lowestDirtyLine;
3016 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3017 afterLowest = lowestDirtyLine;
3018 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3019 }
3020
3021 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3022 afterLowest->markDirty();
3023 afterLowest = afterLowest->prevRootBox();
3024 }
3025}
3026
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003027Optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003028{
3029 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003030 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003031
3032 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003033 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003034
antti@apple.com940f5872013-10-24 20:31:11 +00003035 if (!hasLines())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003036 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003037
darin@apple.come1be6ca2014-04-28 04:19:10 +00003038 if (auto simpleLineLayout = this->simpleLineLayout())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003039 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003040
akling@apple.comee3c8df2013-11-06 08:09:44 +00003041 ASSERT(firstRootBox());
3042 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003043}
3044
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003045Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003046{
3047 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003048 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003049
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003050 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3051 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3052 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003053 if (!childrenInline()) {
3054 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3055 if (!inlineBlockBaseline)
3056 return inlineBlockBaseline;
3057 lastBaseline = inlineBlockBaseline.value();
3058 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003059 if (!hasLines()) {
3060 if (!hasLineIfEmpty())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003061 return Optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003062 const auto& fontMetrics = firstLineStyle().fontMetrics();
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003063 return Optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003064 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003065 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003066 }
3067
3068 if (auto simpleLineLayout = this->simpleLineLayout())
3069 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3070 else {
3071 bool isFirstLine = lastRootBox() == firstRootBox();
3072 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3073 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3074 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003075 }
3076 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3077 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3078 // enough with the spec to not cause tons of breakages).
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003079 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003080}
3081
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003082void RenderBlockFlow::setSelectionState(SelectionState state)
3083{
3084 if (state != SelectionNone)
3085 ensureLineBoxes();
3086 RenderBoxModelObject::setSelectionState(state);
3087}
3088
weinig@apple.com12840dc2013-10-22 23:59:08 +00003089GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003090 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3091{
antti@apple.comfea51992013-10-28 13:39:23 +00003092 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003093
weinig@apple.com611b9292013-10-20 22:57:54 +00003094 GapRects result;
3095
3096 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3097
antti@apple.com0e632aa2013-10-22 21:03:38 +00003098 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003099 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003100 // 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 +00003101 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3102 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3103 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3104 }
3105 return result;
3106 }
3107
3108 RootInlineBox* lastSelectedLine = 0;
3109 RootInlineBox* curr;
3110 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3111
3112 // Now paint the gaps for the lines.
3113 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3114 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3115 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3116
3117 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003118 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003119 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3120
3121 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3122 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003123 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003124 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3125 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3126 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3127
3128 lastSelectedLine = curr;
3129 }
3130
3131 if (containsStart && !lastSelectedLine)
3132 // VisibleSelection must start just after our last line.
3133 lastSelectedLine = lastRootBox();
3134
3135 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003136 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003137 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3138 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3139 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3140 }
3141 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003142}
3143
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003144void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3145{
dino@apple.coma4a89042016-05-06 21:21:20 +00003146 if (renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003147 return;
3148
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003149 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3150 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003151 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003152 flowFragment->initializeStyle();
zalan@apple.comfcaf5c22016-01-15 21:49:33 +00003153 addChild(flowFragment);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003154 setRenderNamedFlowFragment(flowFragment);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003155 }
3156}
3157
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003158bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3159{
3160 // A block without floats or that expands to enclose them won't need a relayout
3161 // after a region range change. There is no overflow content needing relayout
3162 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003163 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003164 return false;
3165
3166 return true;
3167}
3168
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003169bool RenderBlockFlow::canHaveChildren() const
3170{
3171 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3172}
3173
3174bool RenderBlockFlow::canHaveGeneratedChildren() const
3175{
3176 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3177}
3178
3179bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3180{
3181 if (!isRenderNamedFlowFragmentContainer())
3182 return false;
3183
3184 return hasRelativeLogicalHeight() && !isRenderView();
3185}
3186
3187void RenderBlockFlow::updateLogicalHeight()
3188{
3189 RenderBlock::updateLogicalHeight();
3190
abucur@adobe.comfad53712014-05-06 17:30:40 +00003191 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003192 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003193 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3194 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003195}
3196
3197void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3198{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003199 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
zalan@apple.comfcaf5c22016-01-15 21:49:33 +00003200 if (auto* flowFragmentOnFlow = std::exchange(rareData.m_renderNamedFlowFragment, nullptr))
3201 flowFragmentOnFlow->destroy();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003202 rareData.m_renderNamedFlowFragment = flowFragment;
3203}
3204
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003205void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3206{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003207 if (flowThread || hasRareBlockFlowData()) {
3208 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3209 rareData.m_multiColumnFlowThread = flowThread;
3210 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003211}
3212
akling@apple.com525dae62014-01-03 20:22:09 +00003213static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003214{
akling@apple.com38f0a652014-02-06 21:24:17 +00003215 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003216}
3217
3218RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3219{
3220 ASSERT(i >= 0);
3221
akling@apple.com827be9c2013-10-29 02:58:43 +00003222 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003223 return nullptr;
3224
3225 if (childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003226 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003227 if (!i--)
3228 return box;
3229 }
akling@apple.com525dae62014-01-03 20:22:09 +00003230 return nullptr;
3231 }
3232
3233 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3234 if (!shouldCheckLines(blockFlow))
3235 continue;
3236 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3237 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003238 }
3239
3240 return nullptr;
3241}
3242
3243int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3244{
akling@apple.com827be9c2013-10-29 02:58:43 +00003245 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003246 return 0;
3247
3248 int count = 0;
3249
3250 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003251 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003252 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003253 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003254 }
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003255 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3256 ++count;
weinig@apple.com17140912013-10-19 19:55:40 +00003257 if (box == stopRootInlineBox) {
3258 if (found)
3259 *found = true;
3260 break;
3261 }
3262 }
akling@apple.com525dae62014-01-03 20:22:09 +00003263 return count;
3264 }
3265
3266 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3267 if (!shouldCheckLines(blockFlow))
3268 continue;
3269 bool recursiveFound = false;
3270 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3271 if (recursiveFound) {
3272 if (found)
3273 *found = true;
3274 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003275 }
3276 }
3277
3278 return count;
3279}
3280
3281static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3282{
akling@apple.com827be9c2013-10-29 02:58:43 +00003283 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003284 return -1;
3285
3286 if (block.childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003287 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003288 if (++count == lineCount)
3289 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3290 }
3291 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003292 RenderBox* normalFlowChildWithoutLines = nullptr;
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003293 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003294 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3295 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003296 if (result != -1)
3297 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003298 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003299 normalFlowChildWithoutLines = obj;
3300 }
3301 if (normalFlowChildWithoutLines && !lineCount)
3302 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3303 }
3304
3305 return -1;
3306}
3307
3308int RenderBlockFlow::heightForLineCount(int lineCount)
3309{
3310 int count = 0;
3311 return getHeightForLineCount(*this, lineCount, true, count);
3312}
3313
3314void RenderBlockFlow::clearTruncation()
3315{
akling@apple.com827be9c2013-10-29 02:58:43 +00003316 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003317 return;
3318
3319 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003320 ensureLineBoxes();
3321
weinig@apple.com17140912013-10-19 19:55:40 +00003322 setHasMarkupTruncation(false);
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003323 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
weinig@apple.com17140912013-10-19 19:55:40 +00003324 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003325 return;
3326 }
3327
3328 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3329 if (shouldCheckLines(blockFlow))
3330 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003331 }
3332}
3333
weinig@apple.com3f23b382013-10-19 20:26:58 +00003334bool RenderBlockFlow::containsNonZeroBidiLevel() const
3335{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003336 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3337 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003338 if (box->bidiLevel())
3339 return true;
3340 }
3341 }
3342 return false;
3343}
3344
weinig@apple.com611b9292013-10-20 22:57:54 +00003345Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3346{
3347 if (!box)
3348 return Position();
3349
3350 if (!box->renderer().nonPseudoNode())
3351 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3352
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003353 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003354 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3355
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003356 auto& textBox = downcast<InlineTextBox>(*box);
3357 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003358}
3359
enrica@apple.com0db51a62016-04-27 23:53:08 +00003360RenderText* RenderBlockFlow::findClosestTextAtAbsolutePoint(const FloatPoint& point)
3361{
3362 // A light, non-recursive version of RenderBlock::positionForCoordinates that looks at
3363 // whether a point lies within the gaps between its root line boxes, to be called against
3364 // a node returned from elementAtPoint. We make the assumption that either the node or one
3365 // of its immediate children contains the root line boxes in question.
3366 // See <rdar://problem/6824650> for context.
3367
3368 RenderBlock* block = this;
3369
3370 FloatPoint localPoint = block->absoluteToLocal(point);
3371
3372 if (!block->childrenInline()) {
3373 // Look among our immediate children for an alternate box that contains the point.
3374 for (RenderBox* child = block->firstChildBox(); child; child = child->nextSiblingBox()) {
3375 if (!child->height() || child->style().visibility() != WebCore::VISIBLE || child->isFloatingOrOutOfFlowPositioned())
3376 continue;
3377 float top = child->y();
3378
3379 RenderBox* nextChild = child->nextSiblingBox();
3380 while (nextChild && nextChild->isFloatingOrOutOfFlowPositioned())
3381 nextChild = nextChild->nextSiblingBox();
3382 if (!nextChild) {
3383 if (localPoint.y() >= top) {
3384 block = downcast<RenderBlock>(child);
3385 break;
3386 }
3387 continue;
3388 }
3389
3390 float bottom = nextChild->y();
3391
3392 if (localPoint.y() >= top && localPoint.y() < bottom && is<RenderBlock>(*child)) {
3393 block = downcast<RenderBlock>(child);
3394 break;
3395 }
3396 }
3397
3398 if (!block->childrenInline())
3399 return nullptr;
3400
3401 localPoint = block->absoluteToLocal(point);
3402 }
3403
3404 RenderBlockFlow& blockFlow = downcast<RenderBlockFlow>(*block);
3405
3406 // Only check the gaps between the root line boxes. We deliberately ignore overflow because
3407 // experience has shown that hit tests on an exploded text node can fail when within the
3408 // overflow region.
3409 for (RootInlineBox* current = blockFlow.firstRootBox(); current && current != blockFlow.lastRootBox(); current = current->nextRootBox()) {
3410 float currentBottom = current->y() + current->logicalHeight();
3411 if (localPoint.y() < currentBottom)
3412 return nullptr;
3413
3414 RootInlineBox* next = current->nextRootBox();
3415 float nextTop = next->y();
3416 if (localPoint.y() < nextTop) {
3417 InlineBox* inlineBox = current->closestLeafChildForLogicalLeftPosition(localPoint.x());
3418 if (inlineBox && inlineBox->behavesLikeText() && is<RenderText>(inlineBox->renderer()))
3419 return &downcast<RenderText>(inlineBox->renderer());
3420 }
3421 }
3422 return nullptr;
3423}
3424
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003425VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003426{
3427 ASSERT(childrenInline());
3428
antti@apple.com940f5872013-10-24 20:31:11 +00003429 ensureLineBoxes();
3430
weinig@apple.com611b9292013-10-20 22:57:54 +00003431 if (!firstRootBox())
3432 return createVisiblePosition(0, DOWNSTREAM);
3433
akling@apple.com827be9c2013-10-29 02:58:43 +00003434 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3435 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003436
3437 // look for the closest line box in the root box which is at the passed-in y coordinate
3438 InlineBox* closestBox = 0;
3439 RootInlineBox* firstRootBoxWithChildren = 0;
3440 RootInlineBox* lastRootBoxWithChildren = 0;
3441 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003442 if (region && root->containingRegion() != region)
3443 continue;
3444
weinig@apple.com611b9292013-10-20 22:57:54 +00003445 if (!root->firstLeafChild())
3446 continue;
3447 if (!firstRootBoxWithChildren)
3448 firstRootBoxWithChildren = root;
3449
3450 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3451 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3452 break;
3453
3454 lastRootBoxWithChildren = root;
3455
3456 // check if this root line box is located at this y coordinate
3457 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3458 if (linesAreFlipped) {
3459 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3460 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3461 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3462
3463 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3464 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3465 continue;
3466 }
3467 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3468 if (closestBox)
3469 break;
3470 }
3471 }
3472
3473 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3474
3475 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3476 // y coordinate is below last root line box, pretend we hit it
3477 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3478 }
3479
3480 if (closestBox) {
3481 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003482 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003483 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3484 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3485 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3486 if (box->isLineBreak()) {
3487 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3488 box = newBox;
3489 }
3490 // y coordinate is above first root line box, so return the start of the first
3491 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3492 }
3493 }
3494
3495 // pass the box a top position that is inside it
3496 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3497 if (!isHorizontalWritingMode())
3498 point = point.transposedPoint();
3499 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003500 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003501 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003502 }
3503
3504 if (lastRootBoxWithChildren) {
3505 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3506 ASSERT(moveCaretToBoundary);
3507 InlineBox* logicallyLastBox;
3508 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3509 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3510 }
3511
3512 // Can't reach this. We have a root line box, but it has no kids.
3513 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3514 // seems to hit this code path.
3515 return createVisiblePosition(0, DOWNSTREAM);
3516}
3517
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003518VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003519{
3520 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003521 return fragment->positionForPoint(point, region);
3522 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003523}
3524
3525
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003526void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
weinig@apple.com611b9292013-10-20 22:57:54 +00003527{
antti@apple.com940f5872013-10-24 20:31:11 +00003528 ASSERT(childrenInline());
weinig@apple.com611b9292013-10-20 22:57:54 +00003529 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003530 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3531 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003532 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3533 if (!rect.isEmpty())
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003534 rects.append(rect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003535 }
3536}
3537
3538void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3539{
3540 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003541
darin@apple.come1be6ca2014-04-28 04:19:10 +00003542 if (auto simpleLineLayout = this->simpleLineLayout()) {
3543 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003544 return;
3545 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003546 m_lineBoxes.paint(this, paintInfo, paintOffset);
3547}
3548
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003549bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003550{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003551 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003552 return false;
3553
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003554 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003555 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3556
3557 bool needsRelayout;
3558 bool neededRelayout = false;
3559 bool firstPass = true;
3560 do {
3561 // Column heights may change here because of balancing. We may have to do multiple layout
3562 // passes, depending on how the contents is fitted to the changed column heights. In most
3563 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3564 // passes than that, though, but the number of retries should not exceed the number of
3565 // columns, unless we have a bug.
3566 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003567 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3568 if (multicolSet->recalculateColumnHeight(firstPass))
3569 needsRelayout = true;
3570 if (needsRelayout) {
3571 // Once a column set gets a new column height, that column set and all successive column
3572 // sets need to be laid out over again, since their logical top will be affected by
3573 // this, and therefore their column heights may change as well, at least if the multicol
3574 // height is constrained.
3575 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003576 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003577 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003578 if (needsRelayout) {
3579 // Layout again. Column balancing resulted in a new height.
3580 neededRelayout = true;
3581 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3582 setChildNeedsLayout(MarkOnlyThis);
3583 if (firstPass)
3584 statePusher.pop();
3585 layoutBlock(false);
3586 }
3587 firstPass = false;
3588 } while (needsRelayout);
3589
3590 multiColumnFlowThread()->setInBalancingPass(false);
3591
3592 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003593}
3594
antti@apple.com940f5872013-10-24 20:31:11 +00003595bool RenderBlockFlow::hasLines() const
3596{
3597 ASSERT(childrenInline());
3598
darin@apple.come1be6ca2014-04-28 04:19:10 +00003599 if (auto simpleLineLayout = this->simpleLineLayout())
3600 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003601
3602 return lineBoxes().firstLineBox();
3603}
3604
antti@apple.com9e891c82014-05-22 06:12:34 +00003605void RenderBlockFlow::invalidateLineLayoutPath()
3606{
akling@apple.coma12fee22015-02-01 02:58:13 +00003607 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003608 case UndeterminedPath:
3609 case ForceLineBoxesPath:
3610 ASSERT(!m_simpleLineLayout);
3611 return;
3612 case LineBoxesPath:
3613 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003614 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003615 return;
3616 case SimpleLinesPath:
3617 // The simple line layout may have become invalid.
3618 m_simpleLineLayout = nullptr;
3619 setNeedsLayout();
akling@apple.coma12fee22015-02-01 02:58:13 +00003620 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003621 return;
3622 }
3623 ASSERT_NOT_REACHED();
3624}
3625
zalan@apple.come37da962014-12-11 03:29:29 +00003626void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003627{
zalan@apple.come37da962014-12-11 03:29:29 +00003628 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3629 if (needsLayout) {
3630 deleteLineBoxesBeforeSimpleLineLayout();
3631 m_simpleLineLayout = SimpleLineLayout::create(*this);
3632 }
antti@apple.com940f5872013-10-24 20:31:11 +00003633 ASSERT(!m_lineBoxes.firstLineBox());
3634
antti@apple.comfea51992013-10-28 13:39:23 +00003635 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003636 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003637 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003638 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003639 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3640}
3641
3642void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3643{
akling@apple.coma12fee22015-02-01 02:58:13 +00003644 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003645 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003646 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3647 if (is<RenderText>(renderer))
3648 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3649 else if (is<RenderLineBreak>(renderer))
3650 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3651 else
3652 ASSERT_NOT_REACHED();
3653 }
antti@apple.com940f5872013-10-24 20:31:11 +00003654}
3655
3656void RenderBlockFlow::ensureLineBoxes()
3657{
akling@apple.coma12fee22015-02-01 02:58:13 +00003658 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003659 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003660 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003661 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003662
3663#if !ASSERT_DISABLED
3664 LayoutUnit oldHeight = logicalHeight();
3665#endif
3666 bool didNeedLayout = needsLayout();
3667
3668 bool relayoutChildren = false;
3669 LayoutUnit repaintLogicalTop;
3670 LayoutUnit repaintLogicalBottom;
3671 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3672
3673 updateLogicalHeight();
3674 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3675
3676 if (!didNeedLayout)
3677 clearNeedsLayout();
3678}
3679
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003680#if ENABLE(TREE_DEBUGGING)
zalan@apple.comfac337f2014-08-29 17:55:34 +00003681void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003682{
weinig@apple.com611b9292013-10-20 22:57:54 +00003683 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003684 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003685
3686 if (auto simpleLineLayout = this->simpleLineLayout())
3687 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003688}
3689#endif
3690
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003691RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3692{
3693 if (hasRareBlockFlowData())
3694 return *m_rareBlockFlowData;
3695 materializeRareBlockFlowData();
3696 return *m_rareBlockFlowData;
3697}
3698
3699void RenderBlockFlow::materializeRareBlockFlowData()
3700{
3701 ASSERT(!hasRareBlockFlowData());
3702 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3703}
3704
aestes@apple.com6751d842014-01-12 02:51:25 +00003705#if ENABLE(IOS_TEXT_AUTOSIZING)
3706inline static bool isVisibleRenderText(RenderObject* renderer)
3707{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003708 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003709 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003710 RenderText& renderText = downcast<RenderText>(*renderer);
3711 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003712}
3713
3714inline static bool resizeTextPermitted(RenderObject* render)
3715{
3716 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3717 auto renderer = render->parent();
3718 while (renderer) {
3719 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003720 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003721 const HTMLElement& element = downcast<HTMLElement>(*renderer->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 }
3724 renderer = renderer->parent();
3725 }
3726 return true;
3727}
3728
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003729int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003730{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003731 if (style().visibility() != VISIBLE)
3732 return 0;
3733 if (childrenInline())
3734 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003735 // Only descend into list items.
3736 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003737 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3738 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003739 return count;
3740}
3741
simon.fraser@apple.comc002ad22016-05-09 21:57:43 +00003742static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject& render)
aestes@apple.com6751d842014-01-12 02:51:25 +00003743{
simon.fraser@apple.comc002ad22016-05-09 21:57:43 +00003744 if (!render.isRenderBlock())
aestes@apple.com6751d842014-01-12 02:51:25 +00003745 return true;
simon.fraser@apple.comc002ad22016-05-09 21:57:43 +00003746 if (render.isListItem())
3747 return render.style().height().type() != Fixed;
aestes@apple.com6751d842014-01-12 02:51:25 +00003748 return false;
3749}
3750
3751// For now, we auto size single lines of text the same as multiple lines.
3752// We've been experimenting with low values for single lines of text.
3753static inline float oneLineTextMultiplier(float specifiedSize)
3754{
3755 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3756}
3757
3758static inline float textMultiplier(float specifiedSize)
3759{
3760 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3761}
3762
3763void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3764{
simon.fraser@apple.com36676e52016-05-07 00:05:58 +00003765 LOG(TextAutosizing, "RenderBlockFlow %p adjustComputedFontSizes, size=%f visibleWidth=%f, width()=%f. Bailing: %d", this, size, visibleWidth, width().toFloat(), visibleWidth >= width());
3766
aestes@apple.com6751d842014-01-12 02:51:25 +00003767 // Don't do any work if the block is smaller than the visible area.
3768 if (visibleWidth >= width())
3769 return;
3770
3771 unsigned lineCount;
3772 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003773 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003774 if (!count)
3775 lineCount = NO_LINE;
3776 else if (count == 1)
3777 lineCount = ONE_LINE;
3778 else
3779 lineCount = MULTI_LINE;
3780 } else
3781 lineCount = m_lineCountForTextAutosizing;
3782
3783 ASSERT(lineCount != NOT_SET);
3784 if (lineCount == NO_LINE)
3785 return;
3786
3787 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3788 float scale = visibleWidth / actualWidth;
3789 float minFontSize = roundf(size / scale);
3790
3791 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3792 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
simon.fraser@apple.comc002ad22016-05-09 21:57:43 +00003793 auto& text = downcast<RenderText>(*descendent);
antti@apple.com5c4302b2016-04-26 18:20:09 +00003794 auto& oldStyle = text.style();
antti@apple.com214b7162015-09-16 00:16:58 +00003795 auto fontDescription = oldStyle.fontDescription();
aestes@apple.com6751d842014-01-12 02:51:25 +00003796 float specifiedSize = fontDescription.specifiedSize();
3797 float scaledSize = roundf(specifiedSize * scale);
3798 if (scaledSize > 0 && scaledSize < minFontSize) {
3799 // 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.
3800 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3801 if (m_lineCountForTextAutosizing == NOT_SET)
3802 m_lineCountForTextAutosizing = lineCount;
3803 if (m_widthForTextAutosizing == -1)
3804 m_widthForTextAutosizing = actualWidth;
3805
3806 float candidateNewSize = 0;
3807 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3808 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003809 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3810 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003811 }
3812 }
3813 }
3814}
3815#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3816
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003817RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3818{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003819 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3820 if (!flowThread)
3821 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003822
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003823 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003824
3825 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003826 flowThread->setChildNeedsLayout(MarkOnlyThis);
3827
3828 if (flowThread->needsLayout()) {
3829 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3830 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3831
zalan@apple.com9ac63c42016-01-14 20:09:51 +00003832 flowThread->invalidateRegions(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003833 flowThread->setNeedsHeightsRecalculation(true);
3834 flowThread->layout();
3835 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003836 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3837 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3838 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3839 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3840 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3841 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3842 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3843 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003844 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003845 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003846 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003847
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003848 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003849}
3850
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003851void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3852{
3853 if (multiColumnFlowThread())
3854 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003855 if (beforeChild) {
3856 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3857 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3858 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003859 RenderBlock::addChild(newChild, beforeChild);
3860}
3861
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003862void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003863{
3864 if (!documentBeingDestroyed()) {
3865 RenderFlowThread* flowThread = multiColumnFlowThread();
3866 if (flowThread && flowThread != &oldChild)
3867 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3868 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003869 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003870}
3871
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003872void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003873{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003874 // If we don't use columns or flow threads, then bail.
3875 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003876 return;
3877
3878 // We don't actually update any of the variables. We just subclassed to adjust our column height.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003879 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3880 LogicalExtentComputedValues computedValues;
3881 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3882 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003883 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003884 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003885 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3886 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003887 } else if (is<RenderFlowThread>(*this)) {
3888 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003889
3890 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3891 // is known. The page logical height thing in LayoutState is meaningless for flow
3892 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3893 // thread), but as long as it is used universally as a means to determine whether page
3894 // height is known or not, we need this. Page height is unknown when column balancing is
3895 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3896 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3897 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3898 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003899 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003900
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003901 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003902 }
3903}
3904
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003905bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3906{
3907 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3908 // in the RenderView instead.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +00003909 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isDocumentElementRenderer() || isBody());
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003910
3911 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3912}
3913
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003914void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3915{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003916 bool destroyColumns = !requiresColumns(count);
3917 if (destroyColumns) {
3918 if (multiColumnFlowThread())
3919 destroyMultiColumnFlowThread();
3920 } else {
3921 if (!multiColumnFlowThread())
3922 createMultiColumnFlowThread();
3923 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003924 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3925 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003926 }
3927}
3928
cdumez@apple.com78141732014-11-04 23:00:48 +00003929void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003930{
hyatt@apple.com86919862014-01-27 16:27:45 +00003931 if (!multiColumnFlowThread())
3932 return;
3933
3934 bool needsLayout = false;
3935 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003936 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003937 if (oldProgressionIsInline != newProgressionIsInline) {
3938 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3939 needsLayout = true;
3940 }
3941
3942 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003943 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003944 if (oldProgressionIsReversed != newProgressionIsReversed) {
3945 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3946 needsLayout = true;
3947 }
3948
3949 if (needsLayout)
3950 setNeedsLayoutAndPrefWidthsRecalc();
3951}
3952
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003953LayoutUnit RenderBlockFlow::computedColumnWidth() const
3954{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003955 if (multiColumnFlowThread())
3956 return multiColumnFlowThread()->computedColumnWidth();
3957 return contentLogicalWidth();
3958}
3959
3960unsigned RenderBlockFlow::computedColumnCount() const
3961{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003962 if (multiColumnFlowThread())
3963 return multiColumnFlowThread()->computedColumnCount();
3964
3965 return 1;
3966}
3967
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003968bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3969{
3970 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3971 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3972 return hasTopOverflow;
3973
3974 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3975 hasTopOverflow = !hasTopOverflow;
3976
3977 return hasTopOverflow;
3978}
3979
3980bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3981{
3982 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3983 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3984 return hasLeftOverflow;
3985
3986 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3987 hasLeftOverflow = !hasLeftOverflow;
3988
3989 return hasLeftOverflow;
3990}
3991
zalan@apple.comac6956c2014-09-05 14:18:06 +00003992struct InlineMinMaxIterator {
3993/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3994 inline min/max width calculations. Note the following about the way it walks:
3995 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3996 (2) We do not drill into the children of floats or replaced elements, since you can't break
3997 in the middle of such an element.
3998 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3999 distinct borders/margin/padding that contribute to the min/max width.
4000*/
4001 const RenderBlockFlow& parent;
4002 RenderObject* current;
4003 bool endOfInline;
4004 bool initial;
4005
4006 InlineMinMaxIterator(const RenderBlockFlow& p)
4007 : parent(p)
4008 , current(nullptr)
4009 , endOfInline(false)
4010 , initial(true)
4011 { }
4012
4013 RenderObject* next();
4014};
4015
4016RenderObject* InlineMinMaxIterator::next()
4017{
4018 RenderObject* result = nullptr;
4019 bool oldEndOfInline = endOfInline;
4020 endOfInline = false;
4021 do {
4022 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
4023 result = current->firstChildSlow();
4024 else if (initial) {
4025 result = parent.firstChild();
4026 initial = false;
4027 }
4028
4029 if (!result) {
4030 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4031 if (!oldEndOfInline && current && current->isRenderInline()) {
4032 result = current;
4033 endOfInline = true;
4034 break;
4035 }
4036
4037 while (current && current != &parent) {
4038 result = current->nextSibling();
4039 if (result)
4040 break;
4041 current = current->parent();
4042 if (current && current != &parent && current->isRenderInline()) {
4043 result = current;
4044 endOfInline = true;
4045 break;
4046 }
4047 }
4048 }
4049
4050 if (!result)
4051 break;
4052
4053 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4054 break;
4055
4056 current = result;
4057 result = nullptr;
4058 } while (current || current == &parent);
4059 // Update our position.
4060 current = result;
4061 return result;
4062}
4063
4064static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4065{
4066 if (cssUnit.type() != Auto)
4067 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4068 return 0;
4069}
4070
4071static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4072{
4073 const RenderStyle& childStyle = child.style();
4074 if (endOfInline) {
4075 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4076 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4077 child.borderEnd();
4078 }
4079 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4080 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4081 child.borderStart();
4082}
4083
4084static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4085{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004086 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004087 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004088 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004089 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004090 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
mmaxfield@apple.com21a4dcb2016-03-13 00:36:59 +00004091 float spaceWidth = font.width(RenderBlock::constructTextRun(&space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004092 inlineMax -= spaceWidth + font.wordSpacing();
4093 if (inlineMin > inlineMax)
4094 inlineMin = inlineMax;
4095 }
4096}
4097
4098static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4099{
4100 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4101}
4102
4103void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4104{
4105 float inlineMax = 0;
4106 float inlineMin = 0;
4107
4108 const RenderStyle& styleToUse = style();
4109 RenderBlock* containingBlock = this->containingBlock();
4110 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4111
4112 // If we are at the start of a line, we want to ignore all white-space.
4113 // Also strip spaces if we previously had text that ended in a trailing space.
4114 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004115 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004116
4117 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4118 // very specific cirucumstances (in order to match common WinIE renderings).
4119 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4120 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4121
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004122 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004123
4124 InlineMinMaxIterator childIterator(*this);
4125
4126 // Only gets added to the max preffered width once.
4127 bool addedTextIndent = false;
4128 // Signals the text indent was more negative than the min preferred width
4129 bool hasRemainingNegativeTextIndent = false;
4130
4131 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4132 RenderObject* prevFloat = 0;
4133 bool isPrevChildInlineFlow = false;
4134 bool shouldBreakLineAfterText = false;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004135 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation() & FirstHangingPunctuation;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004136 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation() & LastHangingPunctuation;
4137 RenderText* lastText = nullptr;
4138
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004139 bool addedStartPunctuationHang = false;
4140
zalan@apple.comac6956c2014-09-05 14:18:06 +00004141 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004142 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004143 child->style().autoWrap();
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004144 bool isAnonymousInlineBlock = child->isAnonymousInlineBlock();
4145
zalan@apple.comac6956c2014-09-05 14:18:06 +00004146 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004147 // Step One: determine whether or not we need to terminate our current line.
4148 // Each discrete chunk can become the new min-width, if it is the widest chunk
4149 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004150
4151 // Children fall into three categories:
4152 // (1) An inline flow object. These objects always have a min/max of 0,
4153 // and are included in the iteration solely so that their margins can
4154 // be added in.
4155 //
4156 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4157 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004158 // we need to break the current line, and then add in our own margins and min/max
4159 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004160 //
4161 // (3) A text object. Text runs can have breakable characters at the start,
4162 // the middle or the end. They may also lose whitespace off the front if
4163 // we're already ignoring whitespace. In order to compute accurate min-width
4164 // information, we need three pieces of information.
4165 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4166 // starts with whitespace.
4167 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4168 // ends with whitespace.
4169 // (c) the min/max width of the string (trimmed for whitespace).
4170 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004171 // If the text string starts with whitespace, then we need to terminate our current line
4172 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004173 //
4174 // If the text string has a breakable character in the middle, but didn't start
4175 // with whitespace, then we add the width of the first non-breakable run and
4176 // then end the current line. We then need to use the intermediate min/max width
4177 // values (if any of them are larger than our current min/max). We then look at
4178 // the width of the last non-breakable run and use that to start a new line
4179 // (unless we end in whitespace).
4180 const RenderStyle& childStyle = child->style();
4181 float childMin = 0;
4182 float childMax = 0;
4183
4184 if (!child->isText()) {
4185 if (child->isLineBreakOpportunity()) {
4186 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4187 inlineMin = 0;
4188 continue;
4189 }
4190 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004191 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004192 // Add in padding/border/margin from the appropriate side of
4193 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004194 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004195 childMin += bpm;
4196 childMax += bpm;
4197
4198 inlineMin += childMin;
4199 inlineMax += childMax;
4200
4201 child->setPreferredLogicalWidthsDirty(false);
4202 } else {
4203 // Inline replaced elts add in their margins to their min/max values.
hyatt@apple.com14520e42016-04-20 18:01:40 +00004204 if (!child->isFloating())
4205 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004206 LayoutUnit margins = 0;
4207 Length startMargin = childStyle.marginStart();
4208 Length endMargin = childStyle.marginEnd();
4209 if (startMargin.isFixed())
4210 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4211 if (endMargin.isFixed())
4212 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4213 childMin += margins.ceilToFloat();
4214 childMax += margins.ceilToFloat();
4215 }
4216 }
4217
cdumez@apple.comf8022152014-10-15 00:29:51 +00004218 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004219 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004220 // Terminate the current line as far as minwidth is concerned.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004221 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4222 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4223
4224 bool clearPreviousFloat;
4225 if (child->isFloating()) {
4226 clearPreviousFloat = (prevFloat
4227 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4228 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4229 prevFloat = child;
4230 } else
4231 clearPreviousFloat = false;
4232
4233 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004234 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) || isAnonymousInlineBlock) {
4235 if (child->isAnonymousInlineBlock() && styleToUse.collapseWhiteSpace())
4236 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004237 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4238 inlineMin = 0;
4239 }
4240
4241 // If we're supposed to clear the previous float, then terminate maxwidth as well.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004242 if (clearPreviousFloat || isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004243 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4244 inlineMax = 0;
4245 }
4246
4247 // Add in text-indent. This is added in only once.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004248 if (!addedTextIndent && !child->isFloating() && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004249 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4250 childMin += ceiledIndent;
4251 childMax += ceiledIndent;
4252
4253 if (childMin < 0)
4254 textIndent = LayoutUnit::fromFloatCeil(childMin);
4255 else
4256 addedTextIndent = true;
4257 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004258
4259 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating() && !isAnonymousInlineBlock)
4260 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004261
4262 // Add our width to the max.
4263 inlineMax += std::max<float>(0, childMax);
4264
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004265 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004266 if (child->isFloating())
4267 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4268 else
4269 inlineMin += childMin;
4270 } else {
4271 // Now check our line.
4272 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4273
4274 // Now start a new line.
4275 inlineMin = 0;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004276
4277 if (child->isAnonymousInlineBlock()) {
4278 // Terminate max width as well.
4279 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4280 inlineMax = 0;
4281 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004282 }
4283
4284 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4285 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4286 inlineMin = 0;
4287 }
4288
4289 // We are no longer stripping whitespace at the start of a line.
4290 if (!child->isFloating()) {
4291 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004292 trailingSpaceChild = nullptr;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004293 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004294 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004295 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004296 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004297 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004298
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004299 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4300 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004301
4302 // Determine if we have a breakable character. Pass in
4303 // whether or not we should ignore any spaces at the front
4304 // of the string. If those are going to be stripped out,
4305 // then they shouldn't be considered in the breakable char
4306 // check.
4307 bool hasBreakableChar, hasBreak;
4308 float beginMin, endMin;
4309 bool beginWS, endWS;
4310 float beginMax, endMax;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004311 bool strippingBeginWS = stripFrontSpaces;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004312 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004313 hasBreakableChar, hasBreak, beginMax, endMax,
4314 childMin, childMax, stripFrontSpaces);
4315
4316 // This text object will not be rendered, but it may still provide a breaking opportunity.
4317 if (!hasBreak && !childMax) {
4318 if (autoWrap && (beginWS || endWS)) {
4319 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4320 inlineMin = 0;
4321 }
4322 continue;
4323 }
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004324
4325 lastText = &renderText;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004326
4327 if (stripFrontSpaces)
4328 trailingSpaceChild = child;
4329 else
4330 trailingSpaceChild = 0;
4331
4332 // Add in text-indent. This is added in only once.
4333 float ti = 0;
4334 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4335 ti = textIndent.ceilToFloat();
4336 childMin += ti;
4337 beginMin += ti;
4338
4339 // It the text indent negative and larger than the child minimum, we re-use the remainder
4340 // in future minimum calculations, but using the negative value again on the maximum
4341 // will lead to under-counting the max pref width.
4342 if (!addedTextIndent) {
4343 childMax += ti;
4344 beginMax += ti;
4345 addedTextIndent = true;
4346 }
4347
4348 if (childMin < 0) {
4349 textIndent = childMin;
4350 hasRemainingNegativeTextIndent = true;
4351 }
4352 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004353
4354 // See if we have a hanging punctuation situation at the start.
4355 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004356 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4357 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004358 childMin -= hangStartWidth;
4359 beginMin -= hangStartWidth;
4360 childMax -= hangStartWidth;
4361 beginMax -= hangStartWidth;
4362 addedStartPunctuationHang = true;
4363 }
4364
zalan@apple.comac6956c2014-09-05 14:18:06 +00004365 // If we have no breakable characters at all,
4366 // then this is the easy case. We add ourselves to the current
4367 // min and max and continue.
4368 if (!hasBreakableChar)
4369 inlineMin += childMin;
4370 else {
4371 // We have a breakable character. Now we need to know if
4372 // we start and end with whitespace.
4373 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004374 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004375 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4376 } else {
4377 inlineMin += beginMin;
4378 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4379 childMin -= ti;
4380 }
4381
4382 inlineMin = childMin;
4383
4384 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004385 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004386 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4387 inlineMin = 0;
4388 shouldBreakLineAfterText = false;
4389 } else {
4390 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4391 inlineMin = endMin;
4392 shouldBreakLineAfterText = true;
4393 }
4394 }
4395
4396 if (hasBreak) {
4397 inlineMax += beginMax;
4398 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4399 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4400 inlineMax = endMax;
4401 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004402 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004403 } else
4404 inlineMax += std::max<float>(0, childMax);
4405 }
4406
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004407 // Ignore spaces after a list marker and also after an anonymous inline block.
4408 if (child->isListMarker() || isAnonymousInlineBlock)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004409 stripFrontSpaces = true;
4410 } else {
4411 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4412 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4413 inlineMin = inlineMax = 0;
4414 stripFrontSpaces = true;
4415 trailingSpaceChild = 0;
4416 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004417 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004418 }
4419
4420 if (!child->isText() && child->isRenderInline())
4421 isPrevChildInlineFlow = true;
4422 else
4423 isPrevChildInlineFlow = false;
4424
4425 oldAutoWrap = autoWrap;
4426 }
4427
4428 if (styleToUse.collapseWhiteSpace())
4429 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004430
4431 if (canHangPunctuationAtEnd && lastText && lastText->textLength() > 0) {
4432 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->textLength() - 1;
4433 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4434 inlineMin -= endHangWidth;
4435 inlineMax -= endHangWidth;
4436 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004437
4438 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4439 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4440}
4441
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004442}
4443// namespace WebCore