blob: 5e96b4d62f2ffe3cf687ec0cc388773f5f22c1e0 [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"
zalan@apple.comac6956c2014-09-05 14:18:06 +000035#include "RenderCombineText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000036#include "RenderFlowThread.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000037#include "RenderInline.h"
akling@apple.comf3028052013-11-04 08:46:06 +000038#include "RenderIterator.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000039#include "RenderLayer.h"
zalan@apple.com8bf2a912015-04-10 03:15:50 +000040#include "RenderLineBreak.h"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000041#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000042#include "RenderMarquee.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000043#include "RenderMultiColumnFlowThread.h"
44#include "RenderMultiColumnSet.h"
mihnea@adobe.combe79cf12013-10-17 09:02:19 +000045#include "RenderNamedFlowFragment.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000046#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000047#include "RenderText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000048#include "RenderView.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000049#include "Settings.h"
antti@apple.com940f5872013-10-24 20:31:11 +000050#include "SimpleLineLayoutFunctions.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000051#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000052#include "VisiblePosition.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000053#include <wtf/NeverDestroyed.h>
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000054
hyatt@apple.com5388e672013-09-06 20:54:47 +000055namespace WebCore {
56
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000057bool RenderBlock::s_canPropagateFloatIntoSibling = false;
58
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000059struct SameSizeAsMarginInfo {
60 uint32_t bitfields : 16;
61 LayoutUnit margins[2];
62};
63
64COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000065COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000066
67// Our MarginInfo state used when laying out block children.
hyatt@apple.com9a79c622015-09-15 18:38:18 +000068RenderBlockFlow::MarginInfo::MarginInfo(const RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000069 : m_atBeforeSideOfBlock(true)
70 , m_atAfterSideOfBlock(false)
71 , m_hasMarginBeforeQuirk(false)
72 , m_hasMarginAfterQuirk(false)
73 , m_determinedMarginBeforeQuirk(false)
74 , m_discardMargin(false)
75{
akling@apple.com827be9c2013-10-29 02:58:43 +000076 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000077 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000078 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000079
akling@apple.com827be9c2013-10-29 02:58:43 +000080 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000081
82 // If any height other than auto is specified in CSS, then we don't collapse our bottom
83 // margins with our children's margins. To do otherwise would be to risk odd visual
84 // effects when the children overflow out of the parent block and yet still collapse
85 // with it. We also don't collapse if we have any bottom border/padding.
86 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000087 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000088
weinig@apple.com12840dc2013-10-22 23:59:08 +000089 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000090
weinig@apple.com12840dc2013-10-22 23:59:08 +000091 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000092
weinig@apple.com12840dc2013-10-22 23:59:08 +000093 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
94 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000095}
96
akling@apple.com689f7612014-12-14 08:21:05 +000097RenderBlockFlow::RenderBlockFlow(Element& element, Ref<RenderStyle>&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +000098 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +000099#if ENABLE(IOS_TEXT_AUTOSIZING)
100 , m_widthForTextAutosizing(-1)
101 , m_lineCountForTextAutosizing(NOT_SET)
102#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000103{
weinig@apple.com611b9292013-10-20 22:57:54 +0000104 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000105}
106
akling@apple.com689f7612014-12-14 08:21:05 +0000107RenderBlockFlow::RenderBlockFlow(Document& document, Ref<RenderStyle>&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000108 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000109#if ENABLE(IOS_TEXT_AUTOSIZING)
110 , m_widthForTextAutosizing(-1)
111 , m_lineCountForTextAutosizing(NOT_SET)
112#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000113{
weinig@apple.com611b9292013-10-20 22:57:54 +0000114 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000115}
116
117RenderBlockFlow::~RenderBlockFlow()
118{
119}
120
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000121void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000122{
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000123 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
124 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000125 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 +0000126 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000127 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000128 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 +0000129 setMultiColumnFlowThread(flowThread);
130}
131
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000132void RenderBlockFlow::destroyMultiColumnFlowThread()
133{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000134 multiColumnFlowThread()->evacuateAndDestroy();
135 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000136}
137
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000138void RenderBlockFlow::insertedIntoTree()
139{
140 RenderBlock::insertedIntoTree();
141 createRenderNamedFlowFragmentIfNeeded();
142}
143
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000144void RenderBlockFlow::willBeDestroyed()
145{
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000146 if (renderNamedFlowFragment())
zalan@apple.comfcaf5c22016-01-15 21:49:33 +0000147 setRenderNamedFlowFragment(nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +0000148
weinig@apple.com611b9292013-10-20 22:57:54 +0000149 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
150 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
151 destroyLeftoverChildren();
152
weinig@apple.com611b9292013-10-20 22:57:54 +0000153 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000154 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000155 // We can't wait for RenderBox::destroy to clear the selection,
156 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000157 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000158 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000159
160 // If we are an anonymous block, then our line boxes might have children
161 // that will outlast this block. In the non-anonymous block case those
162 // children will be destroyed by the time we return from this function.
163 if (isAnonymousBlock()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +0000164 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000165 while (auto childBox = box->firstChild())
166 childBox->removeFromParent();
167 }
168 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000169 } else if (parent())
170 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000171 }
172
akling@apple.com31dd4f42013-10-30 22:27:59 +0000173 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000174
dbates@webkit.org34f59002014-05-20 20:34:35 +0000175 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000176
177 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
178 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000179}
180
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000181RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
182{
183 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
184 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
185 // to avoid floats.
186 parentHasFloats = false;
187 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
188 if (is<RenderBlockFlow>(*sibling)) {
189 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
190 if (!siblingBlock.avoidsFloats())
191 return &siblingBlock;
192 }
193 if (sibling->isFloating())
194 parentHasFloats = true;
195 }
196 return nullptr;
197}
198
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000199void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000200{
201 if (m_floatingObjects)
202 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
203
204 HashSet<RenderBox*> oldIntrudingFloatSet;
205 if (!childrenInline() && m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000206 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
207 auto end = floatingObjectSet.end();
208 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
209 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000210 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000211 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000212 }
213 }
214
215 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000216 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000217 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000218 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000219 if (!oldIntrudingFloatSet.isEmpty())
220 markAllDescendantsWithFloatsForLayout();
221 return;
222 }
223
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000224 RendererToFloatInfoMap floatMap;
225
226 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000227 if (childrenInline())
228 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
229 else
230 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000231 }
232
233 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
234 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
235 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000236 bool isBlockInsideInline = isAnonymousInlineBlock();
237 if (!is<RenderBlockFlow>(parent()) && !isBlockInsideInline)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000238 return;
239
robert@webkit.org97037ef2013-11-20 19:26:10 +0000240 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
241 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000242 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(isBlockInsideInline ? *containingBlock() : *parent());
243 bool parentHasFloats = isBlockInsideInline ? parentBlock.containsFloats() : false;
244 RenderBlockFlow* previousBlock = nullptr;
245 if (!isBlockInsideInline)
246 previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000247 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000248 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000249 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000250
251 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000252 if (previousBlock)
253 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000254 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000255 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000256 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000257 }
258
259 // 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 +0000260 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000261 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000262
263 if (childrenInline()) {
264 LayoutUnit changeLogicalTop = LayoutUnit::max();
265 LayoutUnit changeLogicalBottom = LayoutUnit::min();
266 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000267 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
268 auto end = floatingObjectSet.end();
269 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000270 const auto& floatingObject = *it->get();
271 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000272 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000273 if (oldFloatingObject) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000274 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
275 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000276 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000277 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000278 } else {
279 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000280 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
281 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000282 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000283 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000284 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000285 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000286 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
287 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000288 }
289 }
290
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000291 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
292 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
293 oldFloatingObject->originatingLine()->markDirty();
294 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000295 } else {
296 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000297 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000298 }
299 }
300 }
301
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000302 auto end = floatMap.end();
303 for (auto it = floatMap.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000304 const auto& floatingObject = *it->value.get();
305 if (!floatingObject.isDescendant()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000306 changeLogicalTop = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000307 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000308 }
309 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000310
311 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
312 } else if (!oldIntrudingFloatSet.isEmpty()) {
313 // If there are previously intruding floats that no longer intrude, then children with floats
314 // should also get layout because they might need their floating object lists cleared.
315 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
316 markAllDescendantsWithFloatsForLayout();
317 else {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000318 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
319 auto end = floatingObjectSet.end();
320 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
321 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000322 if (!oldIntrudingFloatSet.isEmpty())
323 markAllDescendantsWithFloatsForLayout();
324 }
325 }
326}
327
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000328void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
329{
330 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
331 // The min/max intrinsic widths calculated really tell how much space elements need when
332 // laid out inside the columns. In order to eventually end up with the desired column width,
333 // we need to convert them to values pertaining to the multicol container.
334 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
335 LayoutUnit columnWidth;
336 LayoutUnit colGap = columnGap();
337 LayoutUnit gapExtra = (columnCount - 1) * colGap;
338 if (style().hasAutoColumnWidth())
339 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
340 else {
341 columnWidth = style().columnWidth();
342 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
343 }
344 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
345 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
346 // performing a layout pass, but this is not an appropriate time or place for layout. The
347 // good news is that if height is unconstrained and there are no explicit breaks, the
348 // resolved column-count really should be 1.
349 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
350 }
351}
352
353void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
354{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000355 if (childrenInline())
356 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
357 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000358 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
359
360 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
361
362 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
363
364 if (!style().autoWrap() && childrenInline()) {
365 // A horizontal marquee with inline children has no minimum width.
366 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
367 minLogicalWidth = 0;
368 }
369
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000370 if (is<RenderTableCell>(*this)) {
371 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000372 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
373 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
374 }
375
rego@igalia.com76760c72015-05-14 16:37:27 +0000376 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000377 maxLogicalWidth += scrollbarWidth;
378 minLogicalWidth += scrollbarWidth;
379}
380
381bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
382{
383 bool changed = recomputeLogicalWidth();
384
385 LayoutUnit oldColumnWidth = computedColumnWidth();
386 computeColumnCountAndWidth();
387
388 return changed || oldColumnWidth != computedColumnWidth();
389}
390
391LayoutUnit RenderBlockFlow::columnGap() const
392{
393 if (style().hasNormalColumnGap())
394 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
395 return style().columnGap();
396}
397
398void RenderBlockFlow::computeColumnCountAndWidth()
399{
400 // Calculate our column width and column count.
401 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
402 unsigned desiredColumnCount = 1;
403 LayoutUnit desiredColumnWidth = contentLogicalWidth();
404
405 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
406 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
407 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
408 return;
409 }
410
411 LayoutUnit availWidth = desiredColumnWidth;
412 LayoutUnit colGap = columnGap();
413 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
414 int colCount = std::max<int>(1, style().columnCount());
415
416 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
417 desiredColumnCount = colCount;
418 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
419 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
420 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
421 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
422 } else {
423 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
424 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
425 }
426 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
427}
428
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000429void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
430{
431 ASSERT(needsLayout());
432
433 if (!relayoutChildren && simplifiedLayout())
434 return;
435
436 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
437
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000438 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000439 relayoutChildren = true;
440
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000441 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000442
443 LayoutUnit previousHeight = logicalHeight();
444 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
445 // for consistency with other render classes?
446 setLogicalHeight(0);
447
448 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000449 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000450
akling@apple.com827be9c2013-10-29 02:58:43 +0000451 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000452 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000453
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000454 preparePaginationBeforeBlockLayout(relayoutChildren);
abucur@adobe.com0e81bc72013-10-22 14:50:37 +0000455 if (!relayoutChildren)
456 relayoutChildren = namedFlowFragmentNeedsUpdate();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000457
458 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
459 // our current maximal positive and negative margins. These values are used when we
460 // are collapsed with adjacent blocks, so for example, if you have block A and B
461 // collapsing together, then you'd take the maximal positive margin from both A and B
462 // and subtract it from the maximal negative margin from both A and B to get the
463 // true collapsed margin. This algorithm is recursive, so when we finish layout()
464 // our block knows its current maximal positive/negative values.
465 //
466 // Start out by setting our margin values to our current margins. Table cells have
467 // no margins, so we don't fill in the values for table cells.
468 bool isCell = isTableCell();
469 if (!isCell) {
470 initMaxMarginValues();
471
akling@apple.com827be9c2013-10-29 02:58:43 +0000472 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
473 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000474 setPaginationStrut(0);
475 }
476
477 LayoutUnit repaintLogicalTop = 0;
478 LayoutUnit repaintLogicalBottom = 0;
479 LayoutUnit maxFloatLogicalBottom = 0;
480 if (!firstChild() && !isAnonymousBlock())
481 setChildrenInline(true);
482 if (childrenInline())
483 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
484 else
485 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
486
487 // Expand our intrinsic height to encompass floats.
488 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000489 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000490 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
491
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000492 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000493 ASSERT(!shouldBreakAtLineToAvoidWidow());
494 return;
495 }
496
497 // Calculate our new height.
498 LayoutUnit oldHeight = logicalHeight();
499 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
500
501 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
502 // This ensures the size information is correctly computed for the last auto-height region receiving content.
cdumez@apple.com3abcc792014-10-20 03:42:03 +0000503 if (is<RenderFlowThread>(*this))
504 downcast<RenderFlowThread>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000505
506 updateLogicalHeight();
507 LayoutUnit newHeight = logicalHeight();
508 if (oldHeight != newHeight) {
509 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
510 // 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 +0000511 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
512 if (blockFlow.isFloatingOrOutOfFlowPositioned())
513 continue;
514 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
515 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000516 }
517 }
518 }
519
520 bool heightChanged = (previousHeight != newHeight);
521 if (heightChanged)
522 relayoutChildren = true;
523
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000524 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000525
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000526 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
527 computeOverflow(oldClientAfterEdge);
528
529 statePusher.pop();
530
531 fitBorderToLinesIfNeeded();
532
533 if (view().layoutState()->m_pageLogicalHeight)
534 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
535
536 updateLayerTransform();
537
538 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
539 // we overflow or not.
540 updateScrollInfoAfterLayout();
541
542 // FIXME: This repaint logic should be moved into a separate helper function!
543 // Repaint with our new bounds if they are different from our old bounds.
544 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000545 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000546 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
547 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
548 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
549 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
550 if (hasOverflowClip()) {
551 // 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.
552 // 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.
553 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000554 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
555 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000556 }
557
558 LayoutRect repaintRect;
559 if (isHorizontalWritingMode())
560 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
561 else
562 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
563
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000564 if (hasOverflowClip()) {
565 // Adjust repaint rect for scroll offset
566 repaintRect.move(-scrolledContentOffset());
567
568 // Don't allow this rect to spill out of our overflow box.
569 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
570 }
571
572 // Make sure the rect is still non-empty after intersecting for overflow above
573 if (!repaintRect.isEmpty()) {
574 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
575 if (hasReflection())
576 repaintRectangle(reflectedRect(repaintRect));
577 }
578 }
579
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000580 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000581}
582
583void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
584{
585 dirtyForLayoutFromPercentageHeightDescendants();
586
587 LayoutUnit beforeEdge = borderAndPaddingBefore();
588 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
589
590 setLogicalHeight(beforeEdge);
591
592 // Lay out our hypothetical grid line as though it occurs at the top of the block.
593 if (view().layoutState()->lineGrid() == this)
594 layoutLineGridBox();
595
596 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000597 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000598
599 // Fieldsets need to find their legend and position it inside the border of the object.
600 // The legend then gets skipped during normal layout. The same is true for ruby text.
601 // It doesn't get included in the normal layout process but is instead skipped.
602 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
603
604 LayoutUnit previousFloatLogicalBottom = 0;
605 maxFloatLogicalBottom = 0;
606
607 RenderBox* next = firstChildBox();
608
609 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000610 RenderBox& child = *next;
611 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000612
weinig@apple.com12840dc2013-10-22 23:59:08 +0000613 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000614 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
615
616 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
617
weinig@apple.com12840dc2013-10-22 23:59:08 +0000618 if (child.isOutOfFlowPositioned()) {
619 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000620 adjustPositionedBlock(child, marginInfo);
621 continue;
622 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000623 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000624 insertFloatingObject(child);
625 adjustFloatingBlock(marginInfo);
626 continue;
627 }
628
629 // Lay out the child.
630 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
631 }
632
633 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
634 // determining the correct collapsed bottom margin information.
635 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
636}
637
antti@apple.com940f5872013-10-24 20:31:11 +0000638void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
639{
akling@apple.coma12fee22015-02-01 02:58:13 +0000640 if (lineLayoutPath() == UndeterminedPath)
641 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000642
akling@apple.coma12fee22015-02-01 02:58:13 +0000643 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000644 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000645 return;
646 }
647
antti@apple.comfea51992013-10-28 13:39:23 +0000648 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000649 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
650}
651
weinig@apple.com12840dc2013-10-22 23:59:08 +0000652void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000653{
654 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
655 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
656
657 // The child is a normal flow object. Compute the margins we will use for collapsing now.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000658 child.computeAndSetBlockDirectionMargins(this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000659
660 // Try to guess our correct logical top position. In most cases this guess will
661 // be correct. Only if we're wrong (when we compute the real logical top position)
662 // will we have to potentially relayout.
663 LayoutUnit estimateWithoutPagination;
664 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
665
666 // 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 +0000667 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000668 LayoutUnit oldLogicalTop = logicalTopForChild(child);
669
670#if !ASSERT_DISABLED
671 LayoutSize oldLayoutDelta = view().layoutDelta();
672#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000673 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000674 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
675 estimateRegionRangeForBoxChild(child);
676
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000677 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000678 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000679 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000680 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000681 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
682 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
683 // very large elements. If it does the comparison with oldLogicalTop might yield a
684 // false negative as adding and removing margins, borders etc from a saturated number
685 // might yield incorrect results. If this is the case always mark for layout.
686 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000687 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000688 // If an element might be affected by the presence of floats, then always mark it for
689 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000690 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000691 if (fb > logicalTopEstimate)
692 markDescendantsWithFloats = true;
693 }
694
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000695 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000696 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000697 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000698 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000699 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000700 }
701
hyatt@apple.comccad3742015-02-04 21:39:00 +0000702 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000703
weinig@apple.com12840dc2013-10-22 23:59:08 +0000704 bool childHadLayout = child.everHadLayout();
705 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000706 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000707 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000708
709 // Cache if we are at the top of the block right now.
710 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
711
712 // Now determine the correct ypos based off examination of collapsing margin
713 // values.
714 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
715
716 // Now check for clear.
717 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
718
719 bool paginated = view().layoutState()->isPaginated();
720 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000721 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000722
723 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
724
725 // Now we have a final top position. See if it really does end up being different from our estimate.
726 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
727 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000728 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
729 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000730 // The child's width depends on the line width. When the child shifts to clear an item, its width can
731 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000732 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000733 }
734
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000735 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000736 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000737 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000738 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000739 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000740 }
741
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000742 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000743 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000744
745 // In case our guess was wrong, relayout the child.
746 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000747
748 // We are no longer at the top of the block if we encounter a non-empty child.
749 // 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 +0000750 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000751 marginInfo.setAtBeforeSideOfBlock(false);
752
753 // Now place the child in the correct left position
754 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
755
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000756 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000757 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000758 if (mustSeparateMarginAfterForChild(child)) {
759 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
760 marginInfo.clearMargin();
761 }
762 // If the child has overhanging floats that intrude into following siblings (or possibly out
763 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000764 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000765 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000766
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000767 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000768 if (childOffset.width() || childOffset.height()) {
769 view().addLayoutDelta(childOffset);
770
771 // If the child moved, we have to repaint it as well as any floating/positioned
772 // descendants. An exception is if we need a layout. In this case, we know we're going to
773 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000774 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
775 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000776 }
777
weinig@apple.com12840dc2013-10-22 23:59:08 +0000778 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
779 child.repaint();
780 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000781 }
782
783 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000784 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
785 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000786 // Check for an after page/column break.
787 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
788 if (newHeight != height())
789 setLogicalHeight(newHeight);
790 }
791
792 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
793}
794
weinig@apple.com12840dc2013-10-22 23:59:08 +0000795void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000796{
797 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000798 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000799
800 LayoutUnit logicalTop = logicalHeight();
zalan@apple.com4d97a002016-02-24 17:13:33 +0000801 updateStaticInlinePositionForChild(child, logicalTop, DoNotIndentText);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000802
803 if (!marginInfo.canCollapseWithMarginBefore()) {
804 // Positioned blocks don't collapse margins, so add the margin provided by
805 // the container now. The child's own margin is added later when calculating its logical top.
806 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
807 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
808 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
809 }
810
weinig@apple.com12840dc2013-10-22 23:59:08 +0000811 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000812 if (childLayer->staticBlockPosition() != logicalTop) {
813 childLayer->setStaticBlockPosition(logicalTop);
814 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000815 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000816 }
817}
818
robert@webkit.org97037ef2013-11-20 19:26:10 +0000819LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
820{
821 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000822 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000823 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
824 return marginValuesForChild(*this).positiveMarginBefore();
825 return LayoutUnit();
826}
827
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000828void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
829{
830 LayoutUnit startPosition = borderStart() + paddingStart();
mmaxfield@apple.comaf573be2016-03-12 21:18:25 +0000831 if (style().shouldPlaceBlockDirectionScrollbarOnLeft())
832 startPosition += (style().isLeftToRightDirection() ? 1 : -1) * verticalScrollbarWidth();
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000833 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
834
835 // Add in our start margin.
836 LayoutUnit childMarginStart = marginStartForChild(child);
837 LayoutUnit newPosition = startPosition + childMarginStart;
838
839 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
840 // to shift over as necessary to dodge any floats that might get in the way.
841 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
842 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
843
844 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
845}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000846
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000847void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
848{
849 // The float should be positioned taking into account the bottom margin
850 // of the previous flow. We add that margin into the height, get the
851 // float positioned properly, and then subtract the margin out of the
852 // height again. In the case of self-collapsing blocks, we always just
853 // use the top margins, since the self-collapsing block collapsed its
854 // own bottom margin into its top margin.
855 //
856 // Note also that the previous flow may collapse its margin into the top of
857 // our block. If this is the case, then we do not add the margin in to our
858 // height when computing the position of the float. This condition can be tested
859 // for by simply calling canCollapseWithMarginBefore. See
860 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
861 // an example of this scenario.
862 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
863 setLogicalHeight(logicalHeight() + marginOffset);
864 positionNewFloats();
865 setLogicalHeight(logicalHeight() - marginOffset);
866}
867
zalan@apple.com4d97a002016-02-24 17:13:33 +0000868void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop, IndentTextOrNot shouldIndentText)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000869{
akling@apple.com827be9c2013-10-29 02:58:43 +0000870 if (child.style().isOriginalDisplayInlineType())
zalan@apple.com4d97a002016-02-24 17:13:33 +0000871 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, shouldIndentText));
weinig@apple.com12840dc2013-10-22 23:59:08 +0000872 else
873 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
874}
875
876void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
877{
878 if (flowThreadContainingBlock()) {
879 // Shift the inline position to exclude the region offset.
880 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
881 }
882 child.layer()->setStaticInlinePosition(inlinePosition);
883}
884
885RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000886{
887 LayoutUnit childBeforePositive = 0;
888 LayoutUnit childBeforeNegative = 0;
889 LayoutUnit childAfterPositive = 0;
890 LayoutUnit childAfterNegative = 0;
891
892 LayoutUnit beforeMargin = 0;
893 LayoutUnit afterMargin = 0;
894
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000895 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000896
897 // If the child has the same directionality as we do, then we can just return its
898 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000899 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000900 if (childRenderBlock) {
901 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
902 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
903 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
904 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
905 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000906 beforeMargin = child.marginBefore();
907 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000908 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000909 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000910 // The child has a different directionality. If the child is parallel, then it's just
911 // flipped relative to us. We can use the margins for the opposite edges.
912 if (childRenderBlock) {
913 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
914 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
915 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
916 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
917 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000918 beforeMargin = child.marginAfter();
919 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000920 }
921 } else {
922 // The child is perpendicular to us, which means its margins don't collapse but are on the
923 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
924 beforeMargin = marginBeforeForChild(child);
925 afterMargin = marginAfterForChild(child);
926 }
927
928 // Resolve uncollapsing margins into their positive/negative buckets.
929 if (beforeMargin) {
930 if (beforeMargin > 0)
931 childBeforePositive = beforeMargin;
932 else
933 childBeforeNegative = -beforeMargin;
934 }
935 if (afterMargin) {
936 if (afterMargin > 0)
937 childAfterPositive = afterMargin;
938 else
939 childAfterNegative = -afterMargin;
940 }
941
942 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
943}
944
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000945bool RenderBlockFlow::childrenPreventSelfCollapsing() const
946{
947 if (!childrenInline())
948 return RenderBlock::childrenPreventSelfCollapsing();
949
950 // If the block has inline children, see if we generated any line boxes. If we have any
951 // line boxes, then we can only be self-collapsing if we have nothing but anonymous inline blocks
952 // that are also self-collapsing inside us.
953 if (!hasLines())
954 return false;
955
956 if (simpleLineLayout())
957 return true; // We have simple line layout lines, so we can't be self-collapsing.
958
959 for (auto* child = firstRootBox(); child; child = child->nextRootBox()) {
960 if (!child->hasAnonymousInlineBlock() || !child->anonymousInlineBlock()->isSelfCollapsingBlock())
961 return true;
962 }
963 return false; // We have no line boxes, so we must be self-collapsing.
964}
965
weinig@apple.com12840dc2013-10-22 23:59:08 +0000966LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000967{
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000968 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
969}
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000970
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000971LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
972{
973 bool childDiscardMarginBefore = child ? mustDiscardMarginBeforeForChild(*child) : false;
974 bool childDiscardMarginAfter = child ? mustDiscardMarginAfterForChild(*child) : false;
975 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
976 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
977 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
978
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000979 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
980 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000981
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000982 // Get the four margin values for the child and cache them.
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000983 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000984
985 // Get our max pos and neg top margins.
986 LayoutUnit posTop = childMargins.positiveMarginBefore();
987 LayoutUnit negTop = childMargins.negativeMarginBefore();
988
989 // For self-collapsing blocks, collapse our bottom margins into our
990 // top to get new posTop and negTop values.
991 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000992 posTop = std::max(posTop, childMargins.positiveMarginAfter());
993 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000994 }
995
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000996 if (marginInfo.canCollapseWithMarginBefore()) {
997 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
998 // This child is collapsing with the top of the
999 // block. If it has larger margin values, then we need to update
1000 // our own maximal values.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001001 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +00001002 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001003
1004 // The minute any of the margins involved isn't a quirk, don't
1005 // collapse it away, even if the margin is smaller (www.webreference.com
1006 // has an example of this, a <dt> with 0.8em author-specified inside
1007 // a <dl> inside a <td>.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001008 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001009 setHasMarginBeforeQuirk(false);
1010 marginInfo.setDeterminedMarginBeforeQuirk(true);
1011 }
1012
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001013 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001014 // We have no top margin and our top child has a quirky margin.
1015 // We will pick up this quirky margin and pass it through.
1016 // This deals with the <td><div><p> case.
1017 // Don't do this for a block that split two inlines though. You do
1018 // still apply margins in this case.
1019 setHasMarginBeforeQuirk(true);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001020 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001021 } else
1022 // The before margin of the container will also discard all the margins it is collapsing with.
1023 setMustDiscardMarginBefore();
1024 }
1025
1026 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1027 if (childDiscardMarginBefore) {
1028 marginInfo.setDiscardMargin(true);
1029 marginInfo.clearMargin();
1030 }
1031
1032 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001033 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001034
1035 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1036 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001037
1038 LayoutUnit clearanceForSelfCollapsingBlock;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001039
robert@webkit.org97037ef2013-11-20 19:26:10 +00001040 // 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
1041 // 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
1042 // 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 +00001043 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1044 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001045 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1046 }
1047
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001048 if (childIsSelfCollapsing) {
1049 // 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.
1050 // Also, the child's top position equals the logical height of the container.
1051 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1052 // This child has no height. We need to compute our
1053 // position before we collapse the child's margins together,
1054 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001055 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1056 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001057 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1058
1059 // Now collapse the child's margins together, which means examining our
1060 // bottom margin values as well.
1061 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1062 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1063
1064 if (!marginInfo.canCollapseWithMarginBefore())
1065 // We need to make sure that the position of the self-collapsing block
1066 // is correct, since it could have overflowing content
1067 // that needs to be positioned correctly (e.g., a block that
1068 // had a specified height of 0 but that actually had subcontent).
1069 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1070 }
1071 } else {
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001072 if (child && mustSeparateMarginBeforeForChild(*child)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001073 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1074 // If we are at the before side of the block and we collapse, ignore the computed margin
1075 // and just add the child margin to the container height. This will correctly position
1076 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001077 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001078 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(*child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001079 logicalTop = logicalHeight();
1080 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1081 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1082 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1083 // We're collapsing with a previous sibling's margins and not
1084 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001085 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001086 logicalTop = logicalHeight();
1087 }
1088
1089 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1090
1091 if (!marginInfo.discardMargin()) {
1092 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1093 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1094 } else
1095 marginInfo.clearMargin();
1096
1097 if (marginInfo.margin())
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001098 marginInfo.setHasMarginAfterQuirk(afterQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001099 }
1100
1101 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1102 // collapsed into the page edge.
1103 LayoutState* layoutState = view().layoutState();
1104 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1105 && hasNextPage(beforeCollapseLogicalTop)) {
1106 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001107 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001108 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1109 }
1110
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001111 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001112 // 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
1113 // any floats from the parent will now overhang.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001114 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001115 LayoutUnit oldLogicalHeight = logicalHeight();
1116 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001117 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001118 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001119 setLogicalHeight(oldLogicalHeight);
1120
1121 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1122 // 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
1123 // floats in the parent that overhang |child|'s new logical top.
1124 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001125 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1126 child->setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001127 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001128
1129 return logicalTop;
1130}
1131
weinig@apple.com12840dc2013-10-22 23:59:08 +00001132LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001133{
1134 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1135 if (!heightIncrease)
1136 return yPos;
1137
weinig@apple.com12840dc2013-10-22 23:59:08 +00001138 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001139 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1140
1141 // For self-collapsing blocks that clear, they can still collapse their
1142 // margins with following siblings. Reset the current margins to represent
1143 // the self-collapsing block's margins only.
1144 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001145 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001146 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001147 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1148 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001149 } else
1150 marginInfo.clearMargin();
1151 marginInfo.setDiscardMargin(childDiscardMargin);
1152
1153 // CSS2.1 states:
1154 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1155 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1156 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1157 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1158 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001159 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001160 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1161 wouldCollapseMarginsWithParent = false;
1162 }
1163 if (wouldCollapseMarginsWithParent)
1164 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1165
robert@webkit.org97037ef2013-11-20 19:26:10 +00001166 // 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
1167 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1168 // 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
1169 // margins can collapse at the correct vertical position.
1170 // 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
1171 // (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],
1172 // i.e., clearance = [height of float] - margin-top".
1173 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001174 } else
1175 // Increase our height by the amount we had to clear.
1176 setLogicalHeight(logicalHeight() + heightIncrease);
1177
1178 if (marginInfo.canCollapseWithMarginBefore()) {
1179 // We can no longer collapse with the top of the block since a clear
1180 // occurred. The empty blocks collapse into the cleared block.
1181 // FIXME: This isn't quite correct. Need clarification for what to do
1182 // if the height the cleared block is offset by is smaller than the
1183 // margins involved.
1184 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1185 marginInfo.setAtBeforeSideOfBlock(false);
1186
1187 // 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 +00001188 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001189 }
1190
robert@webkit.org97037ef2013-11-20 19:26:10 +00001191 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001192}
1193
weinig@apple.com12840dc2013-10-22 23:59:08 +00001194void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001195{
1196 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1197 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1198 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001199 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001200 return;
1201
1202 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1203 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001204 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001205 positiveMarginBefore = 0;
1206 negativeMarginBefore = 0;
1207 discardMarginBefore = true;
1208 return;
1209 }
1210
1211 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001212 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1213 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001214
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001215 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001216 return;
1217
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001218 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001219 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001220 return;
1221
weinig@apple.com12840dc2013-10-22 23:59:08 +00001222 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001223 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1224 return;
1225
weinig@apple.com12840dc2013-10-22 23:59:08 +00001226 RenderBox* grandchildBox = childBlock.firstChildBox();
1227 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001228 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1229 break;
1230 }
1231
1232 // 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 +00001233 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001234 return;
1235
1236 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1237 if (grandchildBox->needsLayout()) {
1238 grandchildBox->computeAndSetBlockDirectionMargins(this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001239 if (is<RenderBlock>(*grandchildBox)) {
1240 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1241 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1242 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001243 }
1244 }
1245
1246 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001247 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001248}
1249
weinig@apple.com12840dc2013-10-22 23:59:08 +00001250LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001251{
1252 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1253 // relayout if there are intruding floats.
1254 LayoutUnit logicalTopEstimate = logicalHeight();
1255 if (!marginInfo.canCollapseWithMarginBefore()) {
1256 LayoutUnit positiveMarginBefore = 0;
1257 LayoutUnit negativeMarginBefore = 0;
1258 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001259 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001260 // Try to do a basic estimation of how the collapse is going to go.
1261 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1262 } else {
1263 // Use the cached collapsed margin values from a previous layout. Most of the time they
1264 // will be right.
1265 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001266 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1267 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001268 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1269 }
1270
1271 // Collapse the result with our current margins.
1272 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001273 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001274 }
1275
1276 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1277 // page.
1278 LayoutState* layoutState = view().layoutState();
1279 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1280 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001281 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001282
1283 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1284
1285 estimateWithoutPagination = logicalTopEstimate;
1286
1287 if (layoutState->isPaginated()) {
1288 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1289 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1290
1291 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1292 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1293
cdumez@apple.come9437792014-10-08 23:33:43 +00001294 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1295 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001296 }
1297
1298 return logicalTopEstimate;
1299}
1300
1301void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1302{
1303 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1304 // 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.
1305 // Don't update the max margin values because we won't need them anyway.
1306 if (marginInfo.discardMargin()) {
1307 setMustDiscardMarginAfter();
1308 return;
1309 }
1310
1311 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1312 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001313 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001314
1315 if (!marginInfo.hasMarginAfterQuirk())
1316 setHasMarginAfterQuirk(false);
1317
1318 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1319 // We have no bottom margin and our last child has a quirky margin.
1320 // We will pick up this quirky margin and pass it through.
1321 // This deals with the <td><div><p> case.
1322 setHasMarginAfterQuirk(true);
1323 }
1324}
1325
1326void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1327{
1328 marginInfo.setAtAfterSideOfBlock(true);
1329
robert@webkit.org97037ef2013-11-20 19:26:10 +00001330 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1331 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1332 // to perform now is at the child's margin-top - so adjust our height to that position.
1333 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001334 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1335 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001336
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001337 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001338 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1339 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1340 setLogicalHeight(logicalHeight() + marginInfo.margin());
1341
1342 // Now add in our bottom border/padding.
1343 setLogicalHeight(logicalHeight() + afterSide);
1344
1345 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1346 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001347 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001348
1349 // Update our bottom collapsed margin info.
1350 setCollapsedBottomMargin(marginInfo);
1351}
1352
1353void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1354{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001355 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001356 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001357 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001358 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001359 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001360
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001361 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1362 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001363}
1364
1365void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1366{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001367 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001368 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001369 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001370 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001371 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001372
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001373 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1374 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001375}
1376
1377void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1378{
akling@apple.com827be9c2013-10-29 02:58:43 +00001379 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001380 ASSERT(value);
1381 return;
1382 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001383
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001384 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001385 if (!value)
1386 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001387 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001388 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001389
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001390 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001391}
1392
1393void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1394{
akling@apple.com827be9c2013-10-29 02:58:43 +00001395 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001396 ASSERT(value);
1397 return;
1398 }
1399
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001400 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001401 if (!value)
1402 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001403 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001404 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001405
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001406 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001407}
1408
1409bool RenderBlockFlow::mustDiscardMarginBefore() const
1410{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001411 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001412}
1413
1414bool RenderBlockFlow::mustDiscardMarginAfter() const
1415{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001416 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001417}
1418
weinig@apple.com12840dc2013-10-22 23:59:08 +00001419bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001420{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001421 ASSERT(!child.selfNeedsLayout());
1422 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001423 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001424 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001425 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001426
1427 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1428 // In case the boxes are perpendicular we assume the property is not specified.
1429 return false;
1430}
1431
weinig@apple.com12840dc2013-10-22 23:59:08 +00001432bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001433{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001434 ASSERT(!child.selfNeedsLayout());
1435 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001436 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001437 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001438 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001439
1440 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1441 return false;
1442}
1443
weinig@apple.com12840dc2013-10-22 23:59:08 +00001444bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001445{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001446 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001447 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001448 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001449 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001450 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001451 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001452
1453 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1454 return false;
1455}
1456
weinig@apple.com12840dc2013-10-22 23:59:08 +00001457bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001458{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001459 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001460 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001461 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001462 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001463 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001464 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001465
1466 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1467 return false;
1468}
1469
weinig@apple.com12840dc2013-10-22 23:59:08 +00001470static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001471{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001472 RenderBlock* curr = child.containingBlock();
1473 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001474 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001475 return true;
1476 if (curr->isFloatingOrOutOfFlowPositioned())
1477 return false;
1478 curr = curr->containingBlock();
1479 }
1480 return true;
1481}
1482
weinig@apple.com12840dc2013-10-22 23:59:08 +00001483LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001484{
1485 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001486 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001487 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001488 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001489 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 +00001490 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001491 bool checkBeforeAlways = (checkColumnBreaks && child.style().breakBefore() == ColumnBreakBetween)
1492 || (checkPageBreaks && alwaysPageBreak(child.style().breakBefore()))
1493 || (checkRegionBreaks && child.style().breakBefore() == RegionBreakBetween);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001494 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001495 if (checkColumnBreaks) {
1496 if (isInsideMulticolFlowThread)
1497 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001498 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001499 if (checkRegionBreaks) {
1500 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001501 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001502 return logicalOffset + offsetBreakAdjustment;
1503 }
1504 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1505 }
1506 return logicalOffset;
1507}
1508
weinig@apple.com12840dc2013-10-22 23:59:08 +00001509LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001510{
1511 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001512 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001513 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001514 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001515 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 +00001516 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
hyatt@apple.com441ab1d2016-01-30 15:28:48 +00001517 bool checkAfterAlways = (checkColumnBreaks && child.style().breakAfter() == ColumnBreakBetween)
1518 || (checkPageBreaks && alwaysPageBreak(child.style().breakAfter()))
1519 || (checkRegionBreaks && child.style().breakAfter() == RegionBreakBetween);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001520 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1521 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1522
1523 // So our margin doesn't participate in the next collapsing steps.
1524 marginInfo.clearMargin();
1525
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001526 if (checkColumnBreaks) {
1527 if (isInsideMulticolFlowThread)
1528 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001529 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001530 if (checkRegionBreaks) {
1531 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001532 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001533 return logicalOffset + marginOffset + offsetBreakAdjustment;
1534 }
1535 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1536 }
1537 return logicalOffset;
1538}
1539
weinig@apple.com12840dc2013-10-22 23:59:08 +00001540LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001541{
cdumez@apple.come9437792014-10-08 23:33:43 +00001542 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001543
1544 if (estimateWithoutPagination != logicalTopAfterClear) {
1545 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1546 // position.
1547 setLogicalHeight(logicalTopAfterClear);
1548 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1549
weinig@apple.com12840dc2013-10-22 23:59:08 +00001550 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001551 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1552 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001553 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001554 }
1555
1556 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001557 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001558 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001559 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001560 }
1561
1562 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001563 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001564 }
1565
1566 LayoutUnit oldTop = logicalTopAfterClear;
1567
1568 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1569 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1570
1571 if (pageLogicalHeightForOffset(result)) {
1572 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001573 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001574 if (spaceShortage > 0) {
1575 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1576 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1577 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1578 // This should be improved, though, because here we just pretend that the child is
1579 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1580 // where there's no child content, border or padding. In other words, we risk stretching more
1581 // than necessary.
1582 setPageBreak(result, spaceShortage);
1583 }
1584 }
1585
1586 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1587 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1588 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1589
1590 LayoutUnit paginationStrut = 0;
1591 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1592 if (unsplittableAdjustmentDelta)
1593 paginationStrut = unsplittableAdjustmentDelta;
1594 else if (childRenderBlock && childRenderBlock->paginationStrut())
1595 paginationStrut = childRenderBlock->paginationStrut();
1596
1597 if (paginationStrut) {
1598 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1599 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1600 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1601 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1602 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1603 // and pushes to the next page anyway, so not too concerned about it.
1604 setPaginationStrut(result + paginationStrut);
1605 if (childRenderBlock)
1606 childRenderBlock->setPaginationStrut(0);
1607 } else
1608 result += paginationStrut;
1609 }
1610
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001611 // 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 +00001612 setLogicalHeight(logicalHeight() + (result - oldTop));
1613
1614 // Return the final adjusted logical top.
1615 return result;
1616}
1617
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001618static inline LayoutUnit calculateMinimumPageHeight(RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001619{
1620 // We may require a certain minimum number of lines per page in order to satisfy
1621 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001622 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001623 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001624 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001625 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1626 line = line->prevRootBox();
1627
1628 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1629 // adjustLinePositionForPagination() for more details.
1630 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001631 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001632 }
1633 return lineBottom - lineTop;
1634}
1635
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001636static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1637{
bfulgham@apple.com62729772015-04-29 02:26:07 +00001638 const auto& renderer = lineBox.renderer();
1639
1640 if (!renderer.document().settings())
1641 return false;
1642
1643 if (!renderer.document().settings()->appleMailPaginationQuirkEnabled())
1644 return false;
1645
1646 if (renderer.element() && renderer.element()->idForStyleResolution() == AtomicString("messageContentContainer", AtomicString::ConstructFromLiteral))
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001647 return true;
1648
1649 return false;
1650}
1651
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001652void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001653{
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001654 // FIXME: Ignore anonymous inline blocks. Handle the delta already having been set because of
1655 // collapsing margins from a previous anonymous inline block.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001656 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1657 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1658 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1659 // of the first column.
1660 //
1661 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1662 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1663 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1664 // for overflow to occur), and then cache visible overflow for each column rect.
1665 //
1666 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1667 // content that paints in a previous column (and content that paints in the following column).
1668 //
1669 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1670 // at least make positive leading work in typical cases.
1671 //
1672 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1673 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1674 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001675 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001676 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001677 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1678 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001679 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001680 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001681 logicalOffset += delta;
1682 lineBox->setPaginationStrut(0);
1683 lineBox->setIsFirstAfterPageBreak(false);
1684 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1685 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1686 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1687 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001688 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001689 // 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.
1690 // 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 +00001691 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001692 }
1693
1694 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1695 // 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
1696 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1697 // 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
1698 // top of the page.
1699 // 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
1700 // this will be a real-world issue. For now we don't try to deal with this problem.
1701 logicalOffset = intMaxForLayoutUnit;
1702 logicalBottom = intMinForLayoutUnit;
1703 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1704 lineHeight = logicalBottom - logicalOffset;
1705 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1706 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1707 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1708 }
1709
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001710 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001711 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001712
1713 int lineIndex = lineCount(lineBox);
1714 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001715 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001716 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001717 setDidBreakAtLineToAvoidWidow();
1718 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001719 // If we have a non-uniform page height, then we have to shift further possibly.
1720 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1721 return;
1722 if (lineHeight > pageLogicalHeight) {
1723 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001724 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001725 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001726 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1727 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001728 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001729 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1730 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001731 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001732 && !isOutOfFlowPositioned() && !isTableCell()) {
1733 auto firstRootBox = this->firstRootBox();
1734 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1735 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001736 if (needsAppleMailPaginationQuirk(*lineBox))
1737 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001738 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1739 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001740 delta += remainingLogicalHeight;
1741 lineBox->setPaginationStrut(remainingLogicalHeight);
1742 lineBox->setIsFirstAfterPageBreak(true);
1743 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001744 } else if (remainingLogicalHeight == pageLogicalHeight) {
1745 // We're at the very top of a page or column.
1746 if (lineBox != firstRootBox())
1747 lineBox->setIsFirstAfterPageBreak(true);
1748 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1749 setPageBreak(logicalOffset, lineHeight);
1750 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001751}
1752
1753void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1754{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001755 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001756 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1757 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001758}
1759
abucur@adobe.comfc497132013-10-04 08:49:21 +00001760void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1761{
1762 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001763 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001764 return;
1765
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001766 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001767}
1768
1769void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1770{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001771 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001772 return;
1773
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001774 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001775}
1776
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001777void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1778{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001779 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001780 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001781 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001782
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001783 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001784}
1785
1786bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1787{
1788 if (!shouldBreakAtLineToAvoidWidow())
1789 return false;
1790
1791 statePusher.pop();
1792 setEverHadLayout(true);
1793 layoutBlock(false);
1794 return true;
1795}
1796
weinig@apple.com31324fd2013-10-28 19:22:51 +00001797bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1798{
1799 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1800
1801 RenderFlowThread* flowThread = flowThreadContainingBlock();
1802 if (!flowThread)
1803 return true; // Printing and multi-column both make new pages to accommodate content.
1804
1805 // See if we're in the last region.
1806 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001807 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001808 if (!region)
1809 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001810
weinig@apple.com31324fd2013-10-28 19:22:51 +00001811 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001812 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001813 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001814
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001815 RenderRegion* startRegion = nullptr;
1816 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001817 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001818 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001819}
1820
1821LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1822{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001823 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001824 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001825
1826 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001827 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1828 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1829 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1830 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1831 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1832 || !hasNextPage(logicalOffset))
1833 return logicalOffset;
1834 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1835 if (remainingLogicalHeight < childLogicalHeight) {
1836 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1837 return logicalOffset;
1838 return logicalOffset + remainingLogicalHeight;
1839 }
1840 return logicalOffset;
1841}
1842
1843bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1844{
1845 bool checkRegion = false;
1846 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1847 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1848 if (minimumLogicalHeight <= pageLogicalHeight)
1849 return true;
1850 if (!hasNextPage(logicalOffset + adjustment))
1851 return false;
1852 adjustment += pageLogicalHeight;
1853 checkRegion = true;
1854 }
1855 return !checkRegion;
1856}
1857
1858void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1859{
1860 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1861 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1862}
1863
1864void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1865{
1866 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1867 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001868}
1869
1870LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1871{
1872 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1873 if (!pageLogicalHeight)
1874 return logicalOffset;
1875
1876 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1877 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1878 if (pageBoundaryRule == ExcludePageBoundary)
1879 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1880 return logicalOffset + remainingLogicalHeight;
1881}
1882
1883LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1884{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001885 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1886 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1887 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1888 if (!pageLogicalHeight)
1889 return 0;
1890
weinig@apple.com31324fd2013-10-28 19:22:51 +00001891 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1892 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1893
1894 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1895 RenderFlowThread* flowThread = flowThreadContainingBlock();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001896 if (!flowThread)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001897 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001898 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001899}
1900
1901LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1902{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001903 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1904 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1905 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1906 if (!pageLogicalHeight)
1907 return 0;
1908
1909 // Now check for a flow thread.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001910 RenderFlowThread* flowThread = flowThreadContainingBlock();
1911 if (!flowThread)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001912 return pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001913 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1914}
1915
1916LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1917{
1918 offset += offsetFromLogicalTopOfFirstPage();
1919
1920 RenderFlowThread* flowThread = flowThreadContainingBlock();
1921 if (!flowThread) {
1922 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1923 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1924 if (pageBoundaryRule == IncludePageBoundary) {
1925 // If includeBoundaryPoint is true the line exactly on the top edge of a
1926 // column will act as being part of the previous column.
1927 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1928 }
1929 return remainingHeight;
1930 }
1931
1932 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1933}
1934
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001935LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1936{
1937 // This method is required because regions do not fragment monolithic elements but instead
1938 // they let them overflow the region they flow in. This behaviour is different from the
1939 // multicol/printing implementations, which have not yet been updated to correctly handle
1940 // monolithic elements.
1941 // As a result, for the moment, this method will only be used for regions, the multicol and
1942 // printing implementations will stick to the existing behaviour until their fragmentation
1943 // implementation is updated to match the regions implementation.
1944 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1945 return logicalHeightForChild(child);
1946
1947 // For unsplittable elements, this method will just return the height of the element that
1948 // fits into the current region, without the height of the part that overflows the region.
1949 // This is done for all regions, except the last one because in that case, the logical
1950 // height of the flow thread needs to also
1951 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1952 return logicalHeightForChild(child);
1953
1954 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1955 // the entire unsplittable child because any following children will not be moved to the next page
1956 // so they will need to be laid out below the current unsplittable child.
1957 LayoutUnit childLogicalTop = logicalTopForChild(child);
1958 if (!hasNextPage(childLogicalTop))
1959 return logicalHeightForChild(child);
1960
1961 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1962 return std::min(child.logicalHeight(), remainingLogicalHeight);
1963}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001964
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001965void RenderBlockFlow::layoutLineGridBox()
1966{
akling@apple.com827be9c2013-10-29 02:58:43 +00001967 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001968 setLineGridBox(0);
1969 return;
1970 }
1971
1972 setLineGridBox(0);
1973
akling@apple.com1aa97b02013-10-31 21:59:49 +00001974 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001975 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1976 lineGridBox->setConstructed();
1977 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1978 VerticalPositionCache verticalPositionCache;
1979 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1980
aestes@apple.com13aae082016-01-02 08:03:08 +00001981 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001982
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001983 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1984 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1985 // to this grid.
1986}
1987
weinig@apple.com12840dc2013-10-22 23:59:08 +00001988bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001989{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001990 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001991}
1992
1993void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1994{
1995 RenderBlock::styleDidChange(diff, oldStyle);
1996
1997 // After our style changed, if we lose our ability to propagate floats into next sibling
1998 // blocks, then we need to find the top most parent containing that overhanging float and
1999 // then mark its descendants with floats for layout and clear all floats from its next
2000 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
2001 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
2002 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2003 RenderBlockFlow* parentBlock = this;
2004 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002005
weinig@apple.comc77041e2013-12-14 18:05:45 +00002006 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2007 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00002008 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00002009 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002010 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2011 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002012 if (ancestor.hasOverhangingFloat(renderer)) {
2013 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002014 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002015 }
2016 }
2017 }
2018 }
2019
2020 parentBlock->markAllDescendantsWithFloatsForLayout();
2021 parentBlock->markSiblingsWithFloatsForLayout();
2022 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002023
akling@apple.com8f40c5b2013-10-27 22:54:07 +00002024 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00002025 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00002026
antti@apple.com9e891c82014-05-22 06:12:34 +00002027 if (diff >= StyleDifferenceRepaint) {
2028 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2029 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2030 invalidateLineLayoutPath();
2031 }
2032
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002033 if (multiColumnFlowThread())
2034 updateStylesForColumnChildren();
2035}
2036
2037void RenderBlockFlow::updateStylesForColumnChildren()
2038{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002039 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002040 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002041}
2042
akling@apple.combdae43242013-10-25 12:00:20 +00002043void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002044{
akling@apple.com827be9c2013-10-29 02:58:43 +00002045 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002046 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2047
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002048 if (oldStyle) {
2049 EPosition oldPosition = oldStyle->position();
2050 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002051
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002052 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2053 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2054 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002055 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002056 }
2057
2058 RenderBlock::styleWillChange(diff, newStyle);
2059}
2060
antti@apple.coma2c7f242013-10-22 22:37:25 +00002061void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002062{
2063 if (containsFloats())
2064 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002065
antti@apple.comfea51992013-10-28 13:39:23 +00002066 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002067 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002068 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002069 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002070 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002071
antti@apple.coma2c7f242013-10-22 22:37:25 +00002072 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002073}
2074
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002075void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002076{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002077 // When a portion of the render tree is being detached, anonymous blocks
2078 // will be combined as their children are deleted. In this process, the
2079 // anonymous block later in the tree is merged into the one preceeding it.
2080 // It can happen that the later block (this) contains floats that the
2081 // previous block (toBlockFlow) did not contain, and thus are not in the
2082 // floating objects list for toBlockFlow. This can result in toBlockFlow
2083 // containing floats that are not in it's floating objects list, but are in
2084 // the floating objects lists of siblings and parents. This can cause
2085 // problems when the float itself is deleted, since the deletion code
2086 // assumes that if a float is not in it's containing block's floating
2087 // objects list, it isn't in any floating objects list. In order to
2088 // preserve this condition (removing it has serious performance
2089 // implications), we need to copy the floating objects from the old block
2090 // (this) to the new block (toBlockFlow). The float's metrics will likely
2091 // all be wrong, but since toBlockFlow is already marked for layout, this
2092 // will get fixed before anything gets displayed.
2093 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2094 if (m_floatingObjects) {
2095 if (!toBlockFlow->m_floatingObjects)
2096 toBlockFlow->createFloatingObjects();
2097
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002098 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2099 auto end = fromFloatingObjectSet.end();
2100
2101 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2102 FloatingObject* floatingObject = it->get();
2103
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002104 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002105 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002106 continue;
2107
2108 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2109 }
2110 }
2111}
2112
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002113void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002114{
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002115 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2116 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2117 moveFloatsTo(&toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002118}
2119
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002120void RenderBlockFlow::addOverflowFromFloats()
2121{
2122 if (!m_floatingObjects)
2123 return;
2124
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002125 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2126 auto end = floatingObjectSet.end();
2127 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002128 const auto& floatingObject = *it->get();
2129 if (floatingObject.isDescendant())
2130 addOverflowFromChild(&floatingObject.renderer(), IntSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002131 }
2132}
2133
2134void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2135{
2136 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2137
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002138 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002139 addOverflowFromFloats();
2140}
2141
2142void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2143{
2144 // Repaint any overhanging floats (if we know we're the one to paint them).
2145 // Otherwise, bail out.
2146 if (!hasOverhangingFloats())
2147 return;
2148
2149 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2150 // 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 +00002151 LayoutStateDisabler layoutStateDisabler(view());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002152 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2153 auto end = floatingObjectSet.end();
2154 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002155 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002156 // Only repaint the object if it is overhanging, is not in its own layer, and
2157 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2158 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002159 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002160 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002161 && !renderer.hasSelfPaintingLayer()
2162 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2163 renderer.repaint();
2164 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002165 }
2166 }
2167}
2168
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002169void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002170{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002171 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002172
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002173 if (!multiColumnFlowThread() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002174 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002175
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002176 // Iterate over our children and paint the column rules as needed.
2177 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2178 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2179 columnSet.paintColumnRules(paintInfo, childPoint);
2180 }
2181}
2182
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002183void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2184{
2185 if (!m_floatingObjects)
2186 return;
2187
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002188 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2189 auto end = floatingObjectSet.end();
2190 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002191 const auto& floatingObject = *it->get();
2192 auto& renderer = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002193 // Only paint the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002194 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002195 PaintInfo currentPaintInfo(paintInfo);
2196 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2197 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
zalan@apple.com6816b132015-10-17 19:14:53 +00002198 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject,
2199 LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(floatingObject) - renderer.x(),
2200 paintOffset.y() + yPositionForFloatIncludingMargin(floatingObject) - renderer.y()));
2201 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002202 if (!preservePhase) {
2203 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002204 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002205 currentPaintInfo.phase = PaintPhaseFloat;
zalan@apple.com6816b132015-10-17 19:14:53 +00002206 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002207 currentPaintInfo.phase = PaintPhaseForeground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002208 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002209 currentPaintInfo.phase = PaintPhaseOutline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002210 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002211 }
2212 }
2213 }
2214}
2215
weinig@apple.com12840dc2013-10-22 23:59:08 +00002216void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002217{
2218 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002219 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2220 auto end = floatingObjectSet.end();
2221 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002222 const auto& floatingObject = *it->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002223 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2224 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
zalan@apple.com6816b132015-10-17 19:14:53 +00002225 floatingObject.renderer().width(), floatingObject.renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002226 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002227 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002228 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002229 }
2230 }
2231}
2232
2233void RenderBlockFlow::createFloatingObjects()
2234{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002235 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002236}
2237
2238void RenderBlockFlow::removeFloatingObjects()
2239{
2240 if (!m_floatingObjects)
2241 return;
2242
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002243 markSiblingsWithFloatsForLayout();
2244
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002245 m_floatingObjects->clear();
2246}
2247
weinig@apple.com12840dc2013-10-22 23:59:08 +00002248FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002249{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002250 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002251
2252 // Create the list of special objects if we don't aleady have one
2253 if (!m_floatingObjects)
2254 createFloatingObjects();
2255 else {
2256 // Don't insert the floatingObject again if it's already in the list
2257 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002258 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002259 if (it != floatingObjectSet.end())
2260 return it->get();
2261 }
2262
2263 // Create the special floatingObject entry & append it to the list
2264
weinig@apple.com12840dc2013-10-22 23:59:08 +00002265 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002266
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002267 // 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 +00002268 bool isChildRenderBlock = floatBox.isRenderBlock();
2269 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2270 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002271
2272 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002273 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2274 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002275 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002276 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2277 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002278 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002279 floatBox.updateLogicalWidth();
2280 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002281 }
2282
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002283 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002284
aestes@apple.com13aae082016-01-02 08:03:08 +00002285 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002286}
2287
weinig@apple.com12840dc2013-10-22 23:59:08 +00002288void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002289{
2290 if (m_floatingObjects) {
2291 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002292 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002293 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002294 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002295 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002296 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2297 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002298
2299 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2300 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2301 logicalBottom = LayoutUnit::max();
2302 else {
2303 // Special-case zero- and less-than-zero-height floats: those don't touch
2304 // the line that they're on, but it still needs to be dirtied. This is
2305 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002306 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002307 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002308 if (floatingObject.originatingLine()) {
2309 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002310 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002311 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2312 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002313 }
2314#if !ASSERT_DISABLED
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002315 floatingObject.setOriginatingLine(0);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002316#endif
2317 }
2318 markLinesDirtyInBlockRange(0, logicalBottom);
2319 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002320 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002321 }
2322 }
2323}
2324
2325void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2326{
2327 if (!containsFloats())
2328 return;
2329
2330 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2331 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002332 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002333 m_floatingObjects->remove(curr);
2334 if (floatingObjectSet.isEmpty())
2335 break;
2336 curr = floatingObjectSet.last().get();
2337 }
2338}
2339
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002340LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2341{
2342 LayoutUnit offset = fixedOffset;
2343 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2344 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2345 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2346}
2347
2348LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2349{
2350 LayoutUnit offset = fixedOffset;
2351 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2352 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2353 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2354}
2355
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002356LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject& floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002357{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002358 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002359 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002360 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002361
andersca@apple.com86298632013-11-10 19:32:33 +00002362 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002363
2364 LayoutUnit floatLogicalLeft;
2365
2366 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002367 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2368
2369 if (isInitialLetter) {
2370 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2371 if (letterClearance > 0) {
2372 logicalTopOffset += letterClearance;
2373 setLogicalHeight(logicalHeight() + letterClearance);
2374 }
2375 }
2376
akling@apple.com827be9c2013-10-29 02:58:43 +00002377 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002378 LayoutUnit heightRemainingLeft = 1;
2379 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002380 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2381 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002382 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002383 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002384 if (insideFlowThread) {
2385 // Have to re-evaluate all of our offsets, since they may have changed.
2386 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2387 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002388 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002389 }
2390 }
andersca@apple.com86298632013-11-10 19:32:33 +00002391 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002392 } else {
2393 LayoutUnit heightRemainingLeft = 1;
2394 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002395 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2396 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002397 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002398 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002399 if (insideFlowThread) {
2400 // Have to re-evaluate all of our offsets, since they may have changed.
2401 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2402 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002403 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002404 }
2405 }
2406 // Use the original width of the float here, since the local variable
2407 // |floatLogicalWidth| was capped to the available line width. See
2408 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002409 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002410 }
2411
hyatt@apple.com87515262014-09-04 21:20:12 +00002412 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002413 const RenderStyle& style = firstLineStyle();
2414 const FontMetrics& fontMetrics = style.fontMetrics();
2415 if (fontMetrics.hasCapHeight()) {
2416 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2417 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2418
2419 // Make an adjustment to align with the cap height of a theoretical block line.
2420 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2421 logicalTopOffset += adjustment;
2422
2423 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2424 // positive for raised and negative for sunken).
2425 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2426
2427 // 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.
2428 if (dropHeightDelta < 0) {
2429 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2430 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2431 }
2432
2433 // 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
2434 // empty lines beside the first letter.
2435 if (dropHeightDelta > 0)
2436 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2437 }
2438 }
2439
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002440 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2441}
2442
2443bool RenderBlockFlow::positionNewFloats()
2444{
2445 if (!m_floatingObjects)
2446 return false;
2447
2448 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2449 if (floatingObjectSet.isEmpty())
2450 return false;
2451
2452 // If all floats have already been positioned, then we have no work to do.
2453 if (floatingObjectSet.last()->isPlaced())
2454 return false;
2455
2456 // Move backwards through our floating object list until we find a float that has
2457 // already been positioned. Then we'll be able to move forward, positioning all of
2458 // the new floats that need it.
2459 auto it = floatingObjectSet.end();
2460 --it; // Go to last item.
2461 auto begin = floatingObjectSet.begin();
2462 FloatingObject* lastPlacedFloatingObject = 0;
2463 while (it != begin) {
2464 --it;
2465 if ((*it)->isPlaced()) {
2466 lastPlacedFloatingObject = it->get();
2467 ++it;
2468 break;
2469 }
2470 }
2471
2472 LayoutUnit logicalTop = logicalHeight();
2473
2474 // The float cannot start above the top position of the last positioned float.
2475 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002476 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002477
2478 auto end = floatingObjectSet.end();
2479 // Now walk through the set of unpositioned floats and place them.
2480 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002481 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002482 // The containing block is responsible for positioning floats, so if we have floats in our
2483 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002484 auto& childBox = floatingObject.renderer();
2485 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002486 continue;
2487
akling@apple.com827be9c2013-10-29 02:58:43 +00002488 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002489
weinig@apple.com12840dc2013-10-22 23:59:08 +00002490 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002491
akling@apple.com827be9c2013-10-29 02:58:43 +00002492 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002493 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002494 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002495 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002496
2497 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2498
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002499 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002500
2501 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2502 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2503
2504 estimateRegionRangeForBoxChild(childBox);
2505
hyatt@apple.comccad3742015-02-04 21:39:00 +00002506 childBox.markForPaginationRelayoutIfNeeded();
2507 childBox.layoutIfNeeded();
2508
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002509 LayoutState* layoutState = view().layoutState();
2510 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002511 if (isPaginated) {
2512 // If we are unsplittable and don't fit, then we need to move down.
2513 // We include our margins as part of the unsplittable area.
2514 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2515
2516 // See if we have a pagination strut that is making us move down further.
2517 // Note that an unsplittable child can't also have a pagination strut, so this is
2518 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002519 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002520 if (childBlock && childBlock->paginationStrut()) {
2521 newLogicalTop += childBlock->paginationStrut();
2522 childBlock->setPaginationStrut(0);
2523 }
2524
2525 if (newLogicalTop != floatLogicalLocation.y()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002526 floatingObject.setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002527
2528 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002529 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002530
2531 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2532 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2533
2534 if (childBlock)
2535 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002536 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002537 }
2538
2539 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002540 childBox.setNeedsLayout(MarkOnlyThis);
2541 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002542 }
2543 }
2544
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002545 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002546
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002547 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002548
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002549 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002550
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002551#if ENABLE(CSS_SHAPES)
2552 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002553 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002554#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002555 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002556 if (childBox.checkForRepaintDuringLayout())
2557 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002558 }
2559 return true;
2560}
2561
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002562void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002563{
2564 positionNewFloats();
2565 // set y position
2566 LayoutUnit newY = 0;
2567 switch (clear) {
2568 case CLEFT:
2569 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2570 break;
2571 case CRIGHT:
2572 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2573 break;
2574 case CBOTH:
2575 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002576 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002577 default:
2578 break;
2579 }
2580 if (height() < newY)
2581 setLogicalHeight(newY);
2582}
2583
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002584LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002585{
2586 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002587 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002588
2589 return fixedOffset;
2590}
2591
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002592LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002593{
2594 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002595 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002596
2597 return fixedOffset;
2598}
2599
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002600LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002601{
2602 if (!m_floatingObjects)
2603 return logicalHeight;
2604
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002605 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2606}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002607
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002608LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2609{
2610 if (!m_floatingObjects)
2611 return logicalHeight;
2612
2613 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002614}
2615
2616LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2617{
2618 if (!m_floatingObjects)
2619 return 0;
2620 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002621 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2622 auto end = floatingObjectSet.end();
2623 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002624 const auto& floatingObject = *it->get();
2625 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002626 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002627 }
2628 return lowestFloatBottom;
2629}
2630
hyatt@apple.com87515262014-09-04 21:20:12 +00002631LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2632{
2633 if (!m_floatingObjects)
2634 return 0;
2635 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002636 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2637 auto end = floatingObjectSet.end();
2638 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002639 const auto& floatingObject = *it->get();
2640 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == FIRST_LETTER && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002641 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002642 }
2643 return lowestFloatBottom;
2644}
2645
weinig@apple.com12840dc2013-10-22 23:59:08 +00002646LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002647{
2648 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002649 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002650 return 0;
2651
weinig@apple.com12840dc2013-10-22 23:59:08 +00002652 LayoutUnit childLogicalTop = child.logicalTop();
2653 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002654 LayoutUnit lowestFloatLogicalBottom = 0;
2655
2656 // Floats that will remain the child's responsibility to paint should factor into its
2657 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002658 auto childEnd = child.m_floatingObjects->set().end();
2659 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002660 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002661 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002662 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002663 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002664
2665 if (logicalBottom > logicalHeight()) {
2666 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002667 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002668 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2669 bool shouldPaint = false;
2670
2671 // The nearest enclosing layer always paints the float (so that zindex and stacking
2672 // behaves properly). We always want to propagate the desire to paint the float as
2673 // far out as we can, to the outermost block that overlaps the float, stopping only
2674 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002675 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2676 floatingObject.setShouldPaint(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002677 shouldPaint = true;
2678 }
2679 // We create the floating object list lazily.
2680 if (!m_floatingObjects)
2681 createFloatingObjects();
2682
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002683 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002684 }
2685 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002686 const auto& renderer = floatingObject.renderer();
2687 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2688 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002689 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2690 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2691 // layer.
2692 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2693 // it should paint.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002694 floatingObject.setShouldPaint(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002695 }
2696
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002697 // Since the float doesn't overhang, it didn't get put into our list. We need to add its overflow in to the child now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002698 if (floatingObject.isDescendant())
zalan@apple.com6816b132015-10-17 19:14:53 +00002699 child.addOverflowFromChild(&renderer, LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002700 }
2701 }
2702 return lowestFloatLogicalBottom;
2703}
2704
weinig@apple.com12840dc2013-10-22 23:59:08 +00002705bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002706{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002707 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002708 return false;
2709
2710 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002711 const auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002712 if (it == floatingObjectSet.end())
2713 return false;
2714
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002715 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002716}
2717
hyatt@apple.com21c60802015-04-01 18:10:32 +00002718void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002719{
2720 ASSERT(!avoidsFloats());
2721
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002722 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2723 if (createsNewFormattingContext())
2724 return;
2725
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002726 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2727 if (!prev->m_floatingObjects)
2728 return;
2729
2730 logicalLeftOffset += marginLogicalLeft();
2731
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002732 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2733 auto prevEnd = prevSet.end();
2734 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002735 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002736 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002737 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002738 // We create the floating object list lazily.
2739 if (!m_floatingObjects)
2740 createFloatingObjects();
2741
2742 // Applying the child's margin makes no sense in the case where the child was passed in.
2743 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2744 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2745 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2746 // will get applied twice.
2747 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002748 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2749 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002750
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002751 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002752 }
2753 }
2754 }
2755}
2756
2757void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2758{
2759 if (!everHadLayout() && !containsFloats())
2760 return;
2761
2762 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2763 setChildNeedsLayout(markParents);
2764
2765 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002766 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002767
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002768 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002769 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2770 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2771 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002772 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002773 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2774 block.setChildNeedsLayout(markParents);
2775 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002776 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002777 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002778 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2779 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002780 }
2781}
2782
2783void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2784{
2785 if (!m_floatingObjects)
2786 return;
2787
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002788 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2789 auto end = floatingObjectSet.end();
2790
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002791 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002792 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002793 continue;
2794
cdumez@apple.come9437792014-10-08 23:33:43 +00002795 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002796 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2797 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002798 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002799 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002800 if (nextBlock.containsFloat(floatingBox))
2801 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002802 }
2803 }
2804}
2805
zalan@apple.com6816b132015-10-17 19:14:53 +00002806LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002807{
akling@apple.com827be9c2013-10-29 02:58:43 +00002808 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002809 return point;
2810
2811 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2812 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2813 // case.
2814 if (isHorizontalWritingMode())
zalan@apple.com6816b132015-10-17 19:14:53 +00002815 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2816 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002817}
2818
weinig@apple.com12840dc2013-10-22 23:59:08 +00002819LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002820{
2821 // There is no need to compute clearance if we have no floats.
2822 if (!containsFloats())
2823 return 0;
2824
2825 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002826 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002827 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002828 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002829 case CNONE:
2830 break;
2831 case CLEFT:
2832 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2833 break;
2834 case CRIGHT:
2835 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2836 break;
2837 case CBOTH:
2838 logicalBottom = lowestFloatLogicalBottom();
2839 break;
2840 }
2841
2842 // 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 +00002843 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002844 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002845 LayoutUnit newLogicalTop = logicalTop;
2846 while (true) {
zalan@apple.com64761fe2016-03-02 21:42:22 +00002847 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, DoNotIndentText, logicalHeightForChild(child));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002848 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2849 return newLogicalTop - logicalTop;
2850
2851 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002852 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002853 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2854
2855 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002856 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2857 LayoutUnit childOldMarginLeft = child.marginLeft();
2858 LayoutUnit childOldMarginRight = child.marginRight();
2859 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002860
weinig@apple.com12840dc2013-10-22 23:59:08 +00002861 child.setLogicalTop(newLogicalTop);
2862 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002863 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002864 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002865 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2866
weinig@apple.com12840dc2013-10-22 23:59:08 +00002867 child.setLogicalTop(childOldLogicalTop);
2868 child.setLogicalWidth(childOldLogicalWidth);
2869 child.setMarginLeft(childOldMarginLeft);
2870 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002871
2872 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2873 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2874 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2875 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2876 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002877 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002878 return newLogicalTop - logicalTop;
2879 }
2880
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002881 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002882 ASSERT(newLogicalTop >= logicalTop);
2883 if (newLogicalTop < logicalTop)
2884 break;
2885 }
2886 ASSERT_NOT_REACHED();
2887 }
2888 return result;
2889}
2890
2891bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2892{
2893 if (!m_floatingObjects)
2894 return false;
2895
2896 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002897 if (is<RenderView>(*this))
2898 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002899
2900 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2901 auto begin = floatingObjectSet.begin();
2902 for (auto it = floatingObjectSet.end(); it != begin;) {
2903 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002904 const auto& floatingObject = *it->get();
2905 auto& renderer = floatingObject.renderer();
2906 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
2907 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - renderer.x();
2908 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - renderer.y();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002909 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
zalan@apple.com6816b132015-10-17 19:14:53 +00002910 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002911 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2912 return true;
2913 }
2914 }
2915 }
2916
2917 return false;
2918}
2919
weinig@apple.com611b9292013-10-20 22:57:54 +00002920bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2921{
2922 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002923
darin@apple.come1be6ca2014-04-28 04:19:10 +00002924 if (auto simpleLineLayout = this->simpleLineLayout())
2925 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002926
weinig@apple.com611b9292013-10-20 22:57:54 +00002927 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2928}
2929
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002930void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2931{
akling@apple.com827be9c2013-10-29 02:58:43 +00002932 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002933 return;
2934
2935 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2936 // for either overflow or translations via relative positioning.
2937 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002938 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2939
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002940 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002941 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002942 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002943 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002944 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002945 }
2946 } else {
2947 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2948 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002949 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2950 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002951 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002952 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002953 left = std::min(left, x + obj->x());
2954 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002955 }
2956 }
2957 }
2958 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002959
2960 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002961 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2962 auto end = floatingObjectSet.end();
2963 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002964 const auto& floatingObject = *it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002965 // Only examine the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002966 if (floatingObject.shouldPaint()) {
2967 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(floatingObject) - floatingObject.renderer().x();
2968 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002969 left = std::min(left, floatLeft);
2970 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002971 }
2972 }
2973 }
2974}
2975
2976void RenderBlockFlow::fitBorderToLinesIfNeeded()
2977{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002978 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002979 return;
2980
2981 // Walk any normal flow lines to snugly fit.
2982 LayoutUnit left = LayoutUnit::max();
2983 LayoutUnit right = LayoutUnit::min();
2984 LayoutUnit oldWidth = contentWidth();
2985 adjustForBorderFit(0, left, right);
2986
2987 // Clamp to our existing edges. We can never grow. We only shrink.
2988 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2989 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002990 left = std::min(rightEdge, std::max(leftEdge, left));
2991 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002992
2993 LayoutUnit newContentWidth = right - left;
2994 if (newContentWidth == oldWidth)
2995 return;
2996
2997 setOverrideLogicalContentWidth(newContentWidth);
2998 layoutBlock(false);
2999 clearOverrideLogicalContentWidth();
3000}
3001
3002void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3003{
3004 if (logicalTop >= logicalBottom)
3005 return;
3006
antti@apple.combe9d3e12014-05-11 09:42:47 +00003007 // Floats currently affect the choice whether to use simple line layout path.
3008 if (m_simpleLineLayout) {
3009 invalidateLineLayoutPath();
3010 return;
3011 }
3012
weinig@apple.com611b9292013-10-20 22:57:54 +00003013 RootInlineBox* lowestDirtyLine = lastRootBox();
3014 RootInlineBox* afterLowest = lowestDirtyLine;
3015 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3016 afterLowest = lowestDirtyLine;
3017 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3018 }
3019
3020 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3021 afterLowest->markDirty();
3022 afterLowest = afterLowest->prevRootBox();
3023 }
3024}
3025
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003026Optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003027{
3028 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003029 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003030
3031 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003032 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003033
antti@apple.com940f5872013-10-24 20:31:11 +00003034 if (!hasLines())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003035 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003036
darin@apple.come1be6ca2014-04-28 04:19:10 +00003037 if (auto simpleLineLayout = this->simpleLineLayout())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003038 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003039
akling@apple.comee3c8df2013-11-06 08:09:44 +00003040 ASSERT(firstRootBox());
3041 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003042}
3043
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003044Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003045{
3046 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003047 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003048
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003049 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3050 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3051 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003052 if (!childrenInline()) {
3053 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3054 if (!inlineBlockBaseline)
3055 return inlineBlockBaseline;
3056 lastBaseline = inlineBlockBaseline.value();
3057 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003058 if (!hasLines()) {
3059 if (!hasLineIfEmpty())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003060 return Optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003061 const auto& fontMetrics = firstLineStyle().fontMetrics();
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003062 return Optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003063 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003064 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003065 }
3066
3067 if (auto simpleLineLayout = this->simpleLineLayout())
3068 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3069 else {
3070 bool isFirstLine = lastRootBox() == firstRootBox();
3071 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3072 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3073 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003074 }
3075 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3076 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3077 // enough with the spec to not cause tons of breakages).
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003078 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003079}
3080
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003081void RenderBlockFlow::setSelectionState(SelectionState state)
3082{
3083 if (state != SelectionNone)
3084 ensureLineBoxes();
3085 RenderBoxModelObject::setSelectionState(state);
3086}
3087
weinig@apple.com12840dc2013-10-22 23:59:08 +00003088GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003089 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3090{
antti@apple.comfea51992013-10-28 13:39:23 +00003091 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003092
weinig@apple.com611b9292013-10-20 22:57:54 +00003093 GapRects result;
3094
3095 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3096
antti@apple.com0e632aa2013-10-22 21:03:38 +00003097 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003098 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003099 // Update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this case.
weinig@apple.com611b9292013-10-20 22:57:54 +00003100 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3101 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3102 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3103 }
3104 return result;
3105 }
3106
3107 RootInlineBox* lastSelectedLine = 0;
3108 RootInlineBox* curr;
3109 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3110
3111 // Now paint the gaps for the lines.
3112 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3113 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3114 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3115
3116 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003117 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003118 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3119
3120 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3121 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003122 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003123 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3124 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3125 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3126
3127 lastSelectedLine = curr;
3128 }
3129
3130 if (containsStart && !lastSelectedLine)
3131 // VisibleSelection must start just after our last line.
3132 lastSelectedLine = lastRootBox();
3133
3134 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003135 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003136 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3137 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3138 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3139 }
3140 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003141}
3142
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003143void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3144{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003145 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003146 return;
3147
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003148 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3149 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003150 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003151 flowFragment->initializeStyle();
zalan@apple.comfcaf5c22016-01-15 21:49:33 +00003152 addChild(flowFragment);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003153 setRenderNamedFlowFragment(flowFragment);
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003154 }
3155}
3156
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003157bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3158{
3159 // A block without floats or that expands to enclose them won't need a relayout
3160 // after a region range change. There is no overflow content needing relayout
3161 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003162 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003163 return false;
3164
3165 return true;
3166}
3167
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003168bool RenderBlockFlow::canHaveChildren() const
3169{
3170 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3171}
3172
3173bool RenderBlockFlow::canHaveGeneratedChildren() const
3174{
3175 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3176}
3177
3178bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3179{
3180 if (!isRenderNamedFlowFragmentContainer())
3181 return false;
3182
3183 return hasRelativeLogicalHeight() && !isRenderView();
3184}
3185
3186void RenderBlockFlow::updateLogicalHeight()
3187{
3188 RenderBlock::updateLogicalHeight();
3189
abucur@adobe.comfad53712014-05-06 17:30:40 +00003190 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003191 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003192 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3193 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003194}
3195
3196void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3197{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003198 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
zalan@apple.comfcaf5c22016-01-15 21:49:33 +00003199 if (auto* flowFragmentOnFlow = std::exchange(rareData.m_renderNamedFlowFragment, nullptr))
3200 flowFragmentOnFlow->destroy();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003201 rareData.m_renderNamedFlowFragment = flowFragment;
3202}
3203
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003204void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3205{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003206 if (flowThread || hasRareBlockFlowData()) {
3207 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3208 rareData.m_multiColumnFlowThread = flowThread;
3209 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003210}
3211
akling@apple.com525dae62014-01-03 20:22:09 +00003212static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003213{
akling@apple.com38f0a652014-02-06 21:24:17 +00003214 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003215}
3216
3217RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3218{
3219 ASSERT(i >= 0);
3220
akling@apple.com827be9c2013-10-29 02:58:43 +00003221 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003222 return nullptr;
3223
3224 if (childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003225 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003226 if (!i--)
3227 return box;
3228 }
akling@apple.com525dae62014-01-03 20:22:09 +00003229 return nullptr;
3230 }
3231
3232 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3233 if (!shouldCheckLines(blockFlow))
3234 continue;
3235 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3236 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003237 }
3238
3239 return nullptr;
3240}
3241
3242int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3243{
akling@apple.com827be9c2013-10-29 02:58:43 +00003244 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003245 return 0;
3246
3247 int count = 0;
3248
3249 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003250 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003251 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003252 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003253 }
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003254 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3255 ++count;
weinig@apple.com17140912013-10-19 19:55:40 +00003256 if (box == stopRootInlineBox) {
3257 if (found)
3258 *found = true;
3259 break;
3260 }
3261 }
akling@apple.com525dae62014-01-03 20:22:09 +00003262 return count;
3263 }
3264
3265 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3266 if (!shouldCheckLines(blockFlow))
3267 continue;
3268 bool recursiveFound = false;
3269 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3270 if (recursiveFound) {
3271 if (found)
3272 *found = true;
3273 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003274 }
3275 }
3276
3277 return count;
3278}
3279
3280static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3281{
akling@apple.com827be9c2013-10-29 02:58:43 +00003282 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003283 return -1;
3284
3285 if (block.childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003286 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003287 if (++count == lineCount)
3288 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3289 }
3290 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003291 RenderBox* normalFlowChildWithoutLines = nullptr;
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003292 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003293 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3294 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003295 if (result != -1)
3296 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003297 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003298 normalFlowChildWithoutLines = obj;
3299 }
3300 if (normalFlowChildWithoutLines && !lineCount)
3301 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3302 }
3303
3304 return -1;
3305}
3306
3307int RenderBlockFlow::heightForLineCount(int lineCount)
3308{
3309 int count = 0;
3310 return getHeightForLineCount(*this, lineCount, true, count);
3311}
3312
3313void RenderBlockFlow::clearTruncation()
3314{
akling@apple.com827be9c2013-10-29 02:58:43 +00003315 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003316 return;
3317
3318 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003319 ensureLineBoxes();
3320
weinig@apple.com17140912013-10-19 19:55:40 +00003321 setHasMarkupTruncation(false);
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003322 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
weinig@apple.com17140912013-10-19 19:55:40 +00003323 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003324 return;
3325 }
3326
3327 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3328 if (shouldCheckLines(blockFlow))
3329 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003330 }
3331}
3332
weinig@apple.com3f23b382013-10-19 20:26:58 +00003333bool RenderBlockFlow::containsNonZeroBidiLevel() const
3334{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003335 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3336 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003337 if (box->bidiLevel())
3338 return true;
3339 }
3340 }
3341 return false;
3342}
3343
weinig@apple.com611b9292013-10-20 22:57:54 +00003344Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3345{
3346 if (!box)
3347 return Position();
3348
3349 if (!box->renderer().nonPseudoNode())
3350 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3351
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003352 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003353 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3354
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003355 auto& textBox = downcast<InlineTextBox>(*box);
3356 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003357}
3358
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003359VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003360{
3361 ASSERT(childrenInline());
3362
antti@apple.com940f5872013-10-24 20:31:11 +00003363 ensureLineBoxes();
3364
weinig@apple.com611b9292013-10-20 22:57:54 +00003365 if (!firstRootBox())
3366 return createVisiblePosition(0, DOWNSTREAM);
3367
akling@apple.com827be9c2013-10-29 02:58:43 +00003368 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3369 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003370
3371 // look for the closest line box in the root box which is at the passed-in y coordinate
3372 InlineBox* closestBox = 0;
3373 RootInlineBox* firstRootBoxWithChildren = 0;
3374 RootInlineBox* lastRootBoxWithChildren = 0;
3375 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003376 if (region && root->containingRegion() != region)
3377 continue;
3378
weinig@apple.com611b9292013-10-20 22:57:54 +00003379 if (!root->firstLeafChild())
3380 continue;
3381 if (!firstRootBoxWithChildren)
3382 firstRootBoxWithChildren = root;
3383
3384 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3385 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3386 break;
3387
3388 lastRootBoxWithChildren = root;
3389
3390 // check if this root line box is located at this y coordinate
3391 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3392 if (linesAreFlipped) {
3393 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3394 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3395 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3396
3397 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3398 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3399 continue;
3400 }
3401 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3402 if (closestBox)
3403 break;
3404 }
3405 }
3406
3407 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3408
3409 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3410 // y coordinate is below last root line box, pretend we hit it
3411 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3412 }
3413
3414 if (closestBox) {
3415 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003416 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003417 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3418 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3419 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3420 if (box->isLineBreak()) {
3421 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3422 box = newBox;
3423 }
3424 // y coordinate is above first root line box, so return the start of the first
3425 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3426 }
3427 }
3428
3429 // pass the box a top position that is inside it
3430 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3431 if (!isHorizontalWritingMode())
3432 point = point.transposedPoint();
3433 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003434 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003435 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003436 }
3437
3438 if (lastRootBoxWithChildren) {
3439 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3440 ASSERT(moveCaretToBoundary);
3441 InlineBox* logicallyLastBox;
3442 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3443 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3444 }
3445
3446 // Can't reach this. We have a root line box, but it has no kids.
3447 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3448 // seems to hit this code path.
3449 return createVisiblePosition(0, DOWNSTREAM);
3450}
3451
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003452VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003453{
3454 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003455 return fragment->positionForPoint(point, region);
3456 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003457}
3458
3459
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003460void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
weinig@apple.com611b9292013-10-20 22:57:54 +00003461{
antti@apple.com940f5872013-10-24 20:31:11 +00003462 ASSERT(childrenInline());
weinig@apple.com611b9292013-10-20 22:57:54 +00003463 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003464 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3465 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003466 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3467 if (!rect.isEmpty())
zalan@apple.com8ee1af52016-02-11 22:15:45 +00003468 rects.append(rect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003469 }
3470}
3471
3472void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3473{
3474 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003475
darin@apple.come1be6ca2014-04-28 04:19:10 +00003476 if (auto simpleLineLayout = this->simpleLineLayout()) {
3477 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003478 return;
3479 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003480 m_lineBoxes.paint(this, paintInfo, paintOffset);
3481}
3482
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003483bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003484{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003485 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003486 return false;
3487
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003488 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003489 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3490
3491 bool needsRelayout;
3492 bool neededRelayout = false;
3493 bool firstPass = true;
3494 do {
3495 // Column heights may change here because of balancing. We may have to do multiple layout
3496 // passes, depending on how the contents is fitted to the changed column heights. In most
3497 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3498 // passes than that, though, but the number of retries should not exceed the number of
3499 // columns, unless we have a bug.
3500 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003501 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3502 if (multicolSet->recalculateColumnHeight(firstPass))
3503 needsRelayout = true;
3504 if (needsRelayout) {
3505 // Once a column set gets a new column height, that column set and all successive column
3506 // sets need to be laid out over again, since their logical top will be affected by
3507 // this, and therefore their column heights may change as well, at least if the multicol
3508 // height is constrained.
3509 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003510 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003511 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003512 if (needsRelayout) {
3513 // Layout again. Column balancing resulted in a new height.
3514 neededRelayout = true;
3515 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3516 setChildNeedsLayout(MarkOnlyThis);
3517 if (firstPass)
3518 statePusher.pop();
3519 layoutBlock(false);
3520 }
3521 firstPass = false;
3522 } while (needsRelayout);
3523
3524 multiColumnFlowThread()->setInBalancingPass(false);
3525
3526 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003527}
3528
antti@apple.com940f5872013-10-24 20:31:11 +00003529bool RenderBlockFlow::hasLines() const
3530{
3531 ASSERT(childrenInline());
3532
darin@apple.come1be6ca2014-04-28 04:19:10 +00003533 if (auto simpleLineLayout = this->simpleLineLayout())
3534 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003535
3536 return lineBoxes().firstLineBox();
3537}
3538
antti@apple.com9e891c82014-05-22 06:12:34 +00003539void RenderBlockFlow::invalidateLineLayoutPath()
3540{
akling@apple.coma12fee22015-02-01 02:58:13 +00003541 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003542 case UndeterminedPath:
3543 case ForceLineBoxesPath:
3544 ASSERT(!m_simpleLineLayout);
3545 return;
3546 case LineBoxesPath:
3547 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003548 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003549 return;
3550 case SimpleLinesPath:
3551 // The simple line layout may have become invalid.
3552 m_simpleLineLayout = nullptr;
3553 setNeedsLayout();
akling@apple.coma12fee22015-02-01 02:58:13 +00003554 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003555 return;
3556 }
3557 ASSERT_NOT_REACHED();
3558}
3559
zalan@apple.come37da962014-12-11 03:29:29 +00003560void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003561{
zalan@apple.come37da962014-12-11 03:29:29 +00003562 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3563 if (needsLayout) {
3564 deleteLineBoxesBeforeSimpleLineLayout();
3565 m_simpleLineLayout = SimpleLineLayout::create(*this);
3566 }
antti@apple.com940f5872013-10-24 20:31:11 +00003567 ASSERT(!m_lineBoxes.firstLineBox());
3568
antti@apple.comfea51992013-10-28 13:39:23 +00003569 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003570 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003571 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003572 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003573 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3574}
3575
3576void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3577{
akling@apple.coma12fee22015-02-01 02:58:13 +00003578 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003579 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003580 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3581 if (is<RenderText>(renderer))
3582 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3583 else if (is<RenderLineBreak>(renderer))
3584 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3585 else
3586 ASSERT_NOT_REACHED();
3587 }
antti@apple.com940f5872013-10-24 20:31:11 +00003588}
3589
3590void RenderBlockFlow::ensureLineBoxes()
3591{
akling@apple.coma12fee22015-02-01 02:58:13 +00003592 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003593 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003594 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003595 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003596
3597#if !ASSERT_DISABLED
3598 LayoutUnit oldHeight = logicalHeight();
3599#endif
3600 bool didNeedLayout = needsLayout();
3601
3602 bool relayoutChildren = false;
3603 LayoutUnit repaintLogicalTop;
3604 LayoutUnit repaintLogicalBottom;
3605 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3606
3607 updateLogicalHeight();
3608 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3609
3610 if (!didNeedLayout)
3611 clearNeedsLayout();
3612}
3613
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003614#if ENABLE(TREE_DEBUGGING)
zalan@apple.comfac337f2014-08-29 17:55:34 +00003615void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003616{
weinig@apple.com611b9292013-10-20 22:57:54 +00003617 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003618 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003619
3620 if (auto simpleLineLayout = this->simpleLineLayout())
3621 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003622}
3623#endif
3624
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003625RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3626{
3627 if (hasRareBlockFlowData())
3628 return *m_rareBlockFlowData;
3629 materializeRareBlockFlowData();
3630 return *m_rareBlockFlowData;
3631}
3632
3633void RenderBlockFlow::materializeRareBlockFlowData()
3634{
3635 ASSERT(!hasRareBlockFlowData());
3636 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3637}
3638
aestes@apple.com6751d842014-01-12 02:51:25 +00003639#if ENABLE(IOS_TEXT_AUTOSIZING)
3640inline static bool isVisibleRenderText(RenderObject* renderer)
3641{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003642 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003643 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003644 RenderText& renderText = downcast<RenderText>(*renderer);
3645 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003646}
3647
3648inline static bool resizeTextPermitted(RenderObject* render)
3649{
3650 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3651 auto renderer = render->parent();
3652 while (renderer) {
3653 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003654 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003655 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003656 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003657 }
3658 renderer = renderer->parent();
3659 }
3660 return true;
3661}
3662
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003663int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003664{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003665 if (style().visibility() != VISIBLE)
3666 return 0;
3667 if (childrenInline())
3668 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003669 // Only descend into list items.
3670 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003671 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3672 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003673 return count;
3674}
3675
3676static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3677{
3678 if (!render->isRenderBlock())
3679 return true;
3680 if (render->isListItem())
3681 return render->style().height().type() != Fixed;
3682 return false;
3683}
3684
3685// For now, we auto size single lines of text the same as multiple lines.
3686// We've been experimenting with low values for single lines of text.
3687static inline float oneLineTextMultiplier(float specifiedSize)
3688{
3689 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3690}
3691
3692static inline float textMultiplier(float specifiedSize)
3693{
3694 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3695}
3696
3697void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3698{
3699 // Don't do any work if the block is smaller than the visible area.
3700 if (visibleWidth >= width())
3701 return;
3702
3703 unsigned lineCount;
3704 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003705 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003706 if (!count)
3707 lineCount = NO_LINE;
3708 else if (count == 1)
3709 lineCount = ONE_LINE;
3710 else
3711 lineCount = MULTI_LINE;
3712 } else
3713 lineCount = m_lineCountForTextAutosizing;
3714
3715 ASSERT(lineCount != NOT_SET);
3716 if (lineCount == NO_LINE)
3717 return;
3718
3719 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3720 float scale = visibleWidth / actualWidth;
3721 float minFontSize = roundf(size / scale);
3722
3723 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3724 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003725 RenderText& text = downcast<RenderText>(*descendent);
3726 RenderStyle& oldStyle = text.style();
antti@apple.com214b7162015-09-16 00:16:58 +00003727 auto fontDescription = oldStyle.fontDescription();
aestes@apple.com6751d842014-01-12 02:51:25 +00003728 float specifiedSize = fontDescription.specifiedSize();
3729 float scaledSize = roundf(specifiedSize * scale);
3730 if (scaledSize > 0 && scaledSize < minFontSize) {
3731 // 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.
3732 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3733 if (m_lineCountForTextAutosizing == NOT_SET)
3734 m_lineCountForTextAutosizing = lineCount;
3735 if (m_widthForTextAutosizing == -1)
3736 m_widthForTextAutosizing = actualWidth;
3737
3738 float candidateNewSize = 0;
3739 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3740 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003741 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3742 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003743 }
3744 }
3745 }
3746}
3747#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3748
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003749RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3750{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003751 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3752 if (!flowThread)
3753 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003754
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003755 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003756
3757 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003758 flowThread->setChildNeedsLayout(MarkOnlyThis);
3759
3760 if (flowThread->needsLayout()) {
3761 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3762 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3763
zalan@apple.com9ac63c42016-01-14 20:09:51 +00003764 flowThread->invalidateRegions(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003765 flowThread->setNeedsHeightsRecalculation(true);
3766 flowThread->layout();
3767 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003768 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3769 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3770 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3771 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3772 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3773 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3774 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3775 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003776 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003777 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003778 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003779
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003780 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003781}
3782
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003783void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3784{
3785 if (multiColumnFlowThread())
3786 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003787 if (beforeChild) {
3788 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3789 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3790 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003791 RenderBlock::addChild(newChild, beforeChild);
3792}
3793
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003794void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003795{
3796 if (!documentBeingDestroyed()) {
3797 RenderFlowThread* flowThread = multiColumnFlowThread();
3798 if (flowThread && flowThread != &oldChild)
3799 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3800 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003801 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003802}
3803
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003804void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003805{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003806 // If we don't use columns or flow threads, then bail.
3807 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003808 return;
3809
3810 // 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 +00003811 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3812 LogicalExtentComputedValues computedValues;
3813 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3814 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003815 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003816 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003817 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3818 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003819 } else if (is<RenderFlowThread>(*this)) {
3820 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003821
3822 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3823 // is known. The page logical height thing in LayoutState is meaningless for flow
3824 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3825 // thread), but as long as it is used universally as a means to determine whether page
3826 // height is known or not, we need this. Page height is unknown when column balancing is
3827 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3828 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3829 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3830 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003831 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003832
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003833 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003834 }
3835}
3836
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003837bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3838{
3839 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3840 // in the RenderView instead.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +00003841 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isDocumentElementRenderer() || isBody());
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003842
3843 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3844}
3845
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003846void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3847{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003848 bool destroyColumns = !requiresColumns(count);
3849 if (destroyColumns) {
3850 if (multiColumnFlowThread())
3851 destroyMultiColumnFlowThread();
3852 } else {
3853 if (!multiColumnFlowThread())
3854 createMultiColumnFlowThread();
3855 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003856 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3857 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003858 }
3859}
3860
cdumez@apple.com78141732014-11-04 23:00:48 +00003861void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003862{
hyatt@apple.com86919862014-01-27 16:27:45 +00003863 if (!multiColumnFlowThread())
3864 return;
3865
3866 bool needsLayout = false;
3867 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003868 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003869 if (oldProgressionIsInline != newProgressionIsInline) {
3870 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3871 needsLayout = true;
3872 }
3873
3874 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003875 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003876 if (oldProgressionIsReversed != newProgressionIsReversed) {
3877 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3878 needsLayout = true;
3879 }
3880
3881 if (needsLayout)
3882 setNeedsLayoutAndPrefWidthsRecalc();
3883}
3884
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003885LayoutUnit RenderBlockFlow::computedColumnWidth() const
3886{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003887 if (multiColumnFlowThread())
3888 return multiColumnFlowThread()->computedColumnWidth();
3889 return contentLogicalWidth();
3890}
3891
3892unsigned RenderBlockFlow::computedColumnCount() const
3893{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003894 if (multiColumnFlowThread())
3895 return multiColumnFlowThread()->computedColumnCount();
3896
3897 return 1;
3898}
3899
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003900bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3901{
3902 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3903 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3904 return hasTopOverflow;
3905
3906 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3907 hasTopOverflow = !hasTopOverflow;
3908
3909 return hasTopOverflow;
3910}
3911
3912bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3913{
3914 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3915 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3916 return hasLeftOverflow;
3917
3918 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3919 hasLeftOverflow = !hasLeftOverflow;
3920
3921 return hasLeftOverflow;
3922}
3923
zalan@apple.comac6956c2014-09-05 14:18:06 +00003924struct InlineMinMaxIterator {
3925/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3926 inline min/max width calculations. Note the following about the way it walks:
3927 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3928 (2) We do not drill into the children of floats or replaced elements, since you can't break
3929 in the middle of such an element.
3930 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3931 distinct borders/margin/padding that contribute to the min/max width.
3932*/
3933 const RenderBlockFlow& parent;
3934 RenderObject* current;
3935 bool endOfInline;
3936 bool initial;
3937
3938 InlineMinMaxIterator(const RenderBlockFlow& p)
3939 : parent(p)
3940 , current(nullptr)
3941 , endOfInline(false)
3942 , initial(true)
3943 { }
3944
3945 RenderObject* next();
3946};
3947
3948RenderObject* InlineMinMaxIterator::next()
3949{
3950 RenderObject* result = nullptr;
3951 bool oldEndOfInline = endOfInline;
3952 endOfInline = false;
3953 do {
3954 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3955 result = current->firstChildSlow();
3956 else if (initial) {
3957 result = parent.firstChild();
3958 initial = false;
3959 }
3960
3961 if (!result) {
3962 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3963 if (!oldEndOfInline && current && current->isRenderInline()) {
3964 result = current;
3965 endOfInline = true;
3966 break;
3967 }
3968
3969 while (current && current != &parent) {
3970 result = current->nextSibling();
3971 if (result)
3972 break;
3973 current = current->parent();
3974 if (current && current != &parent && current->isRenderInline()) {
3975 result = current;
3976 endOfInline = true;
3977 break;
3978 }
3979 }
3980 }
3981
3982 if (!result)
3983 break;
3984
3985 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3986 break;
3987
3988 current = result;
3989 result = nullptr;
3990 } while (current || current == &parent);
3991 // Update our position.
3992 current = result;
3993 return result;
3994}
3995
3996static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3997{
3998 if (cssUnit.type() != Auto)
3999 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4000 return 0;
4001}
4002
4003static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4004{
4005 const RenderStyle& childStyle = child.style();
4006 if (endOfInline) {
4007 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4008 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4009 child.borderEnd();
4010 }
4011 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4012 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4013 child.borderStart();
4014}
4015
4016static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4017{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004018 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004019 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004020 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004021 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004022 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004023 float spaceWidth = font.width(RenderBlock::constructTextRun(&renderText, font, &space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004024 inlineMax -= spaceWidth + font.wordSpacing();
4025 if (inlineMin > inlineMax)
4026 inlineMin = inlineMax;
4027 }
4028}
4029
4030static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4031{
4032 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4033}
4034
4035void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4036{
4037 float inlineMax = 0;
4038 float inlineMin = 0;
4039
4040 const RenderStyle& styleToUse = style();
4041 RenderBlock* containingBlock = this->containingBlock();
4042 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4043
4044 // If we are at the start of a line, we want to ignore all white-space.
4045 // Also strip spaces if we previously had text that ended in a trailing space.
4046 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004047 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004048
4049 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4050 // very specific cirucumstances (in order to match common WinIE renderings).
4051 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4052 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4053
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004054 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004055
4056 InlineMinMaxIterator childIterator(*this);
4057
4058 // Only gets added to the max preffered width once.
4059 bool addedTextIndent = false;
4060 // Signals the text indent was more negative than the min preferred width
4061 bool hasRemainingNegativeTextIndent = false;
4062
4063 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4064 RenderObject* prevFloat = 0;
4065 bool isPrevChildInlineFlow = false;
4066 bool shouldBreakLineAfterText = false;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004067 bool canHangPunctuationAtStart = styleToUse.hangingPunctuation() & FirstHangingPunctuation;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004068 bool canHangPunctuationAtEnd = styleToUse.hangingPunctuation() & LastHangingPunctuation;
4069 RenderText* lastText = nullptr;
4070
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004071 bool addedStartPunctuationHang = false;
4072
zalan@apple.comac6956c2014-09-05 14:18:06 +00004073 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004074 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004075 child->style().autoWrap();
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004076 bool isAnonymousInlineBlock = child->isAnonymousInlineBlock();
4077
zalan@apple.comac6956c2014-09-05 14:18:06 +00004078 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004079 // Step One: determine whether or not we need to terminate our current line.
4080 // Each discrete chunk can become the new min-width, if it is the widest chunk
4081 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004082
4083 // Children fall into three categories:
4084 // (1) An inline flow object. These objects always have a min/max of 0,
4085 // and are included in the iteration solely so that their margins can
4086 // be added in.
4087 //
4088 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4089 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004090 // we need to break the current line, and then add in our own margins and min/max
4091 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004092 //
4093 // (3) A text object. Text runs can have breakable characters at the start,
4094 // the middle or the end. They may also lose whitespace off the front if
4095 // we're already ignoring whitespace. In order to compute accurate min-width
4096 // information, we need three pieces of information.
4097 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4098 // starts with whitespace.
4099 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4100 // ends with whitespace.
4101 // (c) the min/max width of the string (trimmed for whitespace).
4102 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004103 // If the text string starts with whitespace, then we need to terminate our current line
4104 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004105 //
4106 // If the text string has a breakable character in the middle, but didn't start
4107 // with whitespace, then we add the width of the first non-breakable run and
4108 // then end the current line. We then need to use the intermediate min/max width
4109 // values (if any of them are larger than our current min/max). We then look at
4110 // the width of the last non-breakable run and use that to start a new line
4111 // (unless we end in whitespace).
4112 const RenderStyle& childStyle = child->style();
4113 float childMin = 0;
4114 float childMax = 0;
4115
4116 if (!child->isText()) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004117 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004118 if (child->isLineBreakOpportunity()) {
4119 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4120 inlineMin = 0;
4121 continue;
4122 }
4123 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004124 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004125 // Add in padding/border/margin from the appropriate side of
4126 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004127 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004128 childMin += bpm;
4129 childMax += bpm;
4130
4131 inlineMin += childMin;
4132 inlineMax += childMax;
4133
4134 child->setPreferredLogicalWidthsDirty(false);
4135 } else {
4136 // Inline replaced elts add in their margins to their min/max values.
4137 LayoutUnit margins = 0;
4138 Length startMargin = childStyle.marginStart();
4139 Length endMargin = childStyle.marginEnd();
4140 if (startMargin.isFixed())
4141 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4142 if (endMargin.isFixed())
4143 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4144 childMin += margins.ceilToFloat();
4145 childMax += margins.ceilToFloat();
4146 }
4147 }
4148
cdumez@apple.comf8022152014-10-15 00:29:51 +00004149 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004150 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004151 // Terminate the current line as far as minwidth is concerned.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004152 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4153 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4154
4155 bool clearPreviousFloat;
4156 if (child->isFloating()) {
4157 clearPreviousFloat = (prevFloat
4158 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4159 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4160 prevFloat = child;
4161 } else
4162 clearPreviousFloat = false;
4163
4164 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004165 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) || isAnonymousInlineBlock) {
4166 if (child->isAnonymousInlineBlock() && styleToUse.collapseWhiteSpace())
4167 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004168 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4169 inlineMin = 0;
4170 }
4171
4172 // If we're supposed to clear the previous float, then terminate maxwidth as well.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004173 if (clearPreviousFloat || isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004174 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4175 inlineMax = 0;
4176 }
4177
4178 // Add in text-indent. This is added in only once.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004179 if (!addedTextIndent && !child->isFloating() && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004180 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4181 childMin += ceiledIndent;
4182 childMax += ceiledIndent;
4183
4184 if (childMin < 0)
4185 textIndent = LayoutUnit::fromFloatCeil(childMin);
4186 else
4187 addedTextIndent = true;
4188 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004189
4190 if (canHangPunctuationAtStart && !addedStartPunctuationHang && !child->isFloating() && !isAnonymousInlineBlock)
4191 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004192
4193 // Add our width to the max.
4194 inlineMax += std::max<float>(0, childMax);
4195
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004196 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004197 if (child->isFloating())
4198 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4199 else
4200 inlineMin += childMin;
4201 } else {
4202 // Now check our line.
4203 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4204
4205 // Now start a new line.
4206 inlineMin = 0;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004207
4208 if (child->isAnonymousInlineBlock()) {
4209 // Terminate max width as well.
4210 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4211 inlineMax = 0;
4212 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004213 }
4214
4215 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4216 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4217 inlineMin = 0;
4218 }
4219
4220 // We are no longer stripping whitespace at the start of a line.
4221 if (!child->isFloating()) {
4222 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004223 trailingSpaceChild = nullptr;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004224 lastText = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004225 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004226 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004227 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004228 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004229
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004230 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4231 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004232
4233 // Determine if we have a breakable character. Pass in
4234 // whether or not we should ignore any spaces at the front
4235 // of the string. If those are going to be stripped out,
4236 // then they shouldn't be considered in the breakable char
4237 // check.
4238 bool hasBreakableChar, hasBreak;
4239 float beginMin, endMin;
4240 bool beginWS, endWS;
4241 float beginMax, endMax;
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004242 bool strippingBeginWS = stripFrontSpaces;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004243 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004244 hasBreakableChar, hasBreak, beginMax, endMax,
4245 childMin, childMax, stripFrontSpaces);
4246
4247 // This text object will not be rendered, but it may still provide a breaking opportunity.
4248 if (!hasBreak && !childMax) {
4249 if (autoWrap && (beginWS || endWS)) {
4250 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4251 inlineMin = 0;
4252 }
4253 continue;
4254 }
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004255
4256 lastText = &renderText;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004257
4258 if (stripFrontSpaces)
4259 trailingSpaceChild = child;
4260 else
4261 trailingSpaceChild = 0;
4262
4263 // Add in text-indent. This is added in only once.
4264 float ti = 0;
4265 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4266 ti = textIndent.ceilToFloat();
4267 childMin += ti;
4268 beginMin += ti;
4269
4270 // It the text indent negative and larger than the child minimum, we re-use the remainder
4271 // in future minimum calculations, but using the negative value again on the maximum
4272 // will lead to under-counting the max pref width.
4273 if (!addedTextIndent) {
4274 childMax += ti;
4275 beginMax += ti;
4276 addedTextIndent = true;
4277 }
4278
4279 if (childMin < 0) {
4280 textIndent = childMin;
4281 hasRemainingNegativeTextIndent = true;
4282 }
4283 }
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004284
4285 // See if we have a hanging punctuation situation at the start.
4286 if (canHangPunctuationAtStart && !addedStartPunctuationHang) {
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004287 unsigned startIndex = strippingBeginWS ? renderText.firstCharacterIndexStrippingSpaces() : 0;
4288 float hangStartWidth = renderText.hangablePunctuationStartWidth(startIndex);
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004289 childMin -= hangStartWidth;
4290 beginMin -= hangStartWidth;
4291 childMax -= hangStartWidth;
4292 beginMax -= hangStartWidth;
4293 addedStartPunctuationHang = true;
4294 }
4295
zalan@apple.comac6956c2014-09-05 14:18:06 +00004296 // If we have no breakable characters at all,
4297 // then this is the easy case. We add ourselves to the current
4298 // min and max and continue.
4299 if (!hasBreakableChar)
4300 inlineMin += childMin;
4301 else {
4302 // We have a breakable character. Now we need to know if
4303 // we start and end with whitespace.
4304 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004305 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004306 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4307 } else {
4308 inlineMin += beginMin;
4309 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4310 childMin -= ti;
4311 }
4312
4313 inlineMin = childMin;
4314
4315 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004316 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004317 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4318 inlineMin = 0;
4319 shouldBreakLineAfterText = false;
4320 } else {
4321 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4322 inlineMin = endMin;
4323 shouldBreakLineAfterText = true;
4324 }
4325 }
4326
4327 if (hasBreak) {
4328 inlineMax += beginMax;
4329 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4330 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4331 inlineMax = endMax;
4332 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004333 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004334 } else
4335 inlineMax += std::max<float>(0, childMax);
4336 }
4337
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004338 // Ignore spaces after a list marker and also after an anonymous inline block.
4339 if (child->isListMarker() || isAnonymousInlineBlock)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004340 stripFrontSpaces = true;
4341 } else {
4342 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4343 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4344 inlineMin = inlineMax = 0;
4345 stripFrontSpaces = true;
4346 trailingSpaceChild = 0;
4347 addedTextIndent = true;
hyatt@apple.com41c12c92016-03-02 22:29:26 +00004348 addedStartPunctuationHang = true;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004349 }
4350
4351 if (!child->isText() && child->isRenderInline())
4352 isPrevChildInlineFlow = true;
4353 else
4354 isPrevChildInlineFlow = false;
4355
4356 oldAutoWrap = autoWrap;
4357 }
4358
4359 if (styleToUse.collapseWhiteSpace())
4360 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
hyatt@apple.com6b422a72016-03-03 21:49:32 +00004361
4362 if (canHangPunctuationAtEnd && lastText && lastText->textLength() > 0) {
4363 unsigned endIndex = trailingSpaceChild == lastText ? lastText->lastCharacterIndexStrippingSpaces() : lastText->textLength() - 1;
4364 float endHangWidth = lastText->hangablePunctuationEndWidth(endIndex);
4365 inlineMin -= endHangWidth;
4366 inlineMax -= endHangWidth;
4367 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004368
4369 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4370 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4371}
4372
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004373}
4374// namespace WebCore