blob: e2ce59af4ca650b4609108b47a84933caa5b8449 [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.
weinig@apple.com12840dc2013-10-22 23:59:08 +000068RenderBlockFlow::MarginInfo::MarginInfo(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)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +000098 : RenderBlock(element, WTF::move(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)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +0000108 : RenderBlock(document, WTF::move(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())
147 setRenderNamedFlowFragment(0);
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()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +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) {
206 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000207 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.
216 if (avoidsFloats() || isRoot() || 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) {
267 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000268 auto end = floatingObjectSet.end();
269 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000270 FloatingObject* floatingObject = it->get();
271 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject->renderer());
272 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000273 if (oldFloatingObject) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000274 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
275 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
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 }
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000283 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
284 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
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
darin@apple.com7cad7042013-09-24 05:53:55 +0000302 auto end = floatMap.end();
303 for (auto it = floatMap.begin(); it != end; ++it) {
304 FloatingObject* floatingObject = it->value.get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000305 if (!floatingObject->isDescendant()) {
306 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +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 {
318 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000319 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
524 layoutPositionedObjects(relayoutChildren || isRoot());
525
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 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
565
566 if (hasOverflowClip()) {
567 // Adjust repaint rect for scroll offset
568 repaintRect.move(-scrolledContentOffset());
569
570 // Don't allow this rect to spill out of our overflow box.
571 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
572 }
573
574 // Make sure the rect is still non-empty after intersecting for overflow above
575 if (!repaintRect.isEmpty()) {
576 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
577 if (hasReflection())
578 repaintRectangle(reflectedRect(repaintRect));
579 }
580 }
581
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000582 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000583}
584
585void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
586{
587 dirtyForLayoutFromPercentageHeightDescendants();
588
589 LayoutUnit beforeEdge = borderAndPaddingBefore();
590 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
591
592 setLogicalHeight(beforeEdge);
593
594 // Lay out our hypothetical grid line as though it occurs at the top of the block.
595 if (view().layoutState()->lineGrid() == this)
596 layoutLineGridBox();
597
598 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000599 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000600
601 // Fieldsets need to find their legend and position it inside the border of the object.
602 // The legend then gets skipped during normal layout. The same is true for ruby text.
603 // It doesn't get included in the normal layout process but is instead skipped.
604 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
605
606 LayoutUnit previousFloatLogicalBottom = 0;
607 maxFloatLogicalBottom = 0;
608
609 RenderBox* next = firstChildBox();
610
611 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000612 RenderBox& child = *next;
613 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000614
weinig@apple.com12840dc2013-10-22 23:59:08 +0000615 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000616 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
617
618 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
619
weinig@apple.com12840dc2013-10-22 23:59:08 +0000620 if (child.isOutOfFlowPositioned()) {
621 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000622 adjustPositionedBlock(child, marginInfo);
623 continue;
624 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000625 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000626 insertFloatingObject(child);
627 adjustFloatingBlock(marginInfo);
628 continue;
629 }
630
631 // Lay out the child.
632 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
633 }
634
635 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
636 // determining the correct collapsed bottom margin information.
637 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
638}
639
antti@apple.com940f5872013-10-24 20:31:11 +0000640void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
641{
akling@apple.coma12fee22015-02-01 02:58:13 +0000642 if (lineLayoutPath() == UndeterminedPath)
643 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000644
akling@apple.coma12fee22015-02-01 02:58:13 +0000645 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000646 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000647 return;
648 }
649
antti@apple.comfea51992013-10-28 13:39:23 +0000650 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000651 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
652}
653
weinig@apple.com12840dc2013-10-22 23:59:08 +0000654void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000655{
656 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
657 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
658
659 // The child is a normal flow object. Compute the margins we will use for collapsing now.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000660 child.computeAndSetBlockDirectionMargins(this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000661
662 // Try to guess our correct logical top position. In most cases this guess will
663 // be correct. Only if we're wrong (when we compute the real logical top position)
664 // will we have to potentially relayout.
665 LayoutUnit estimateWithoutPagination;
666 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
667
668 // 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 +0000669 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000670 LayoutUnit oldLogicalTop = logicalTopForChild(child);
671
672#if !ASSERT_DISABLED
673 LayoutSize oldLayoutDelta = view().layoutDelta();
674#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000675 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000676 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
677 estimateRegionRangeForBoxChild(child);
678
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000679 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000680 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000681 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000682 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000683 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
684 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
685 // very large elements. If it does the comparison with oldLogicalTop might yield a
686 // false negative as adding and removing margins, borders etc from a saturated number
687 // might yield incorrect results. If this is the case always mark for layout.
688 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000689 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000690 // If an element might be affected by the presence of floats, then always mark it for
691 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000692 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000693 if (fb > logicalTopEstimate)
694 markDescendantsWithFloats = true;
695 }
696
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000697 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000698 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000699 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000700 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000701 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000702 }
703
hyatt@apple.comccad3742015-02-04 21:39:00 +0000704 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000705
weinig@apple.com12840dc2013-10-22 23:59:08 +0000706 bool childHadLayout = child.everHadLayout();
707 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000708 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000709 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000710
711 // Cache if we are at the top of the block right now.
712 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
713
714 // Now determine the correct ypos based off examination of collapsing margin
715 // values.
716 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
717
718 // Now check for clear.
719 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
720
721 bool paginated = view().layoutState()->isPaginated();
722 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000723 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000724
725 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
726
727 // Now we have a final top position. See if it really does end up being different from our estimate.
728 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
729 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000730 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
731 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000732 // The child's width depends on the line width. When the child shifts to clear an item, its width can
733 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000734 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000735 }
736
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000737 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000738 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000739 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000740 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000741 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000742 }
743
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000744 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000745 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000746
747 // In case our guess was wrong, relayout the child.
748 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000749
750 // We are no longer at the top of the block if we encounter a non-empty child.
751 // 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 +0000752 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000753 marginInfo.setAtBeforeSideOfBlock(false);
754
755 // Now place the child in the correct left position
756 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
757
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000758 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000759 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000760 if (mustSeparateMarginAfterForChild(child)) {
761 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
762 marginInfo.clearMargin();
763 }
764 // If the child has overhanging floats that intrude into following siblings (or possibly out
765 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000766 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000767 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000768
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000769 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000770 if (childOffset.width() || childOffset.height()) {
771 view().addLayoutDelta(childOffset);
772
773 // If the child moved, we have to repaint it as well as any floating/positioned
774 // descendants. An exception is if we need a layout. In this case, we know we're going to
775 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000776 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
777 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000778 }
779
weinig@apple.com12840dc2013-10-22 23:59:08 +0000780 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
781 child.repaint();
782 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000783 }
784
785 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000786 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
787 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000788 // Check for an after page/column break.
789 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
790 if (newHeight != height())
791 setLogicalHeight(newHeight);
792 }
793
794 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
795}
796
weinig@apple.com12840dc2013-10-22 23:59:08 +0000797void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000798{
799 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000800 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000801
802 LayoutUnit logicalTop = logicalHeight();
803 updateStaticInlinePositionForChild(child, logicalTop);
804
805 if (!marginInfo.canCollapseWithMarginBefore()) {
806 // Positioned blocks don't collapse margins, so add the margin provided by
807 // the container now. The child's own margin is added later when calculating its logical top.
808 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
809 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
810 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
811 }
812
weinig@apple.com12840dc2013-10-22 23:59:08 +0000813 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000814 if (childLayer->staticBlockPosition() != logicalTop) {
815 childLayer->setStaticBlockPosition(logicalTop);
816 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000817 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000818 }
819}
820
robert@webkit.org97037ef2013-11-20 19:26:10 +0000821LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
822{
823 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000824 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000825 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
826 return marginValuesForChild(*this).positiveMarginBefore();
827 return LayoutUnit();
828}
829
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000830void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
831{
832 LayoutUnit startPosition = borderStart() + paddingStart();
833 if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
834 startPosition -= verticalScrollbarWidth();
835 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
836
837 // Add in our start margin.
838 LayoutUnit childMarginStart = marginStartForChild(child);
839 LayoutUnit newPosition = startPosition + childMarginStart;
840
841 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
842 // to shift over as necessary to dodge any floats that might get in the way.
843 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
844 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
845
846 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
847}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000848
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000849void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
850{
851 // The float should be positioned taking into account the bottom margin
852 // of the previous flow. We add that margin into the height, get the
853 // float positioned properly, and then subtract the margin out of the
854 // height again. In the case of self-collapsing blocks, we always just
855 // use the top margins, since the self-collapsing block collapsed its
856 // own bottom margin into its top margin.
857 //
858 // Note also that the previous flow may collapse its margin into the top of
859 // our block. If this is the case, then we do not add the margin in to our
860 // height when computing the position of the float. This condition can be tested
861 // for by simply calling canCollapseWithMarginBefore. See
862 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
863 // an example of this scenario.
864 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
865 setLogicalHeight(logicalHeight() + marginOffset);
866 positionNewFloats();
867 setLogicalHeight(logicalHeight() - marginOffset);
868}
869
weinig@apple.com12840dc2013-10-22 23:59:08 +0000870void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop)
871{
akling@apple.com827be9c2013-10-29 02:58:43 +0000872 if (child.style().isOriginalDisplayInlineType())
weinig@apple.com12840dc2013-10-22 23:59:08 +0000873 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
874 else
875 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
876}
877
878void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
879{
880 if (flowThreadContainingBlock()) {
881 // Shift the inline position to exclude the region offset.
882 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
883 }
884 child.layer()->setStaticInlinePosition(inlinePosition);
885}
886
887RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000888{
889 LayoutUnit childBeforePositive = 0;
890 LayoutUnit childBeforeNegative = 0;
891 LayoutUnit childAfterPositive = 0;
892 LayoutUnit childAfterNegative = 0;
893
894 LayoutUnit beforeMargin = 0;
895 LayoutUnit afterMargin = 0;
896
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000897 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000898
899 // If the child has the same directionality as we do, then we can just return its
900 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000901 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000902 if (childRenderBlock) {
903 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
904 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
905 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
906 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
907 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000908 beforeMargin = child.marginBefore();
909 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000910 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000911 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000912 // The child has a different directionality. If the child is parallel, then it's just
913 // flipped relative to us. We can use the margins for the opposite edges.
914 if (childRenderBlock) {
915 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
916 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
917 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
918 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
919 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000920 beforeMargin = child.marginAfter();
921 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000922 }
923 } else {
924 // The child is perpendicular to us, which means its margins don't collapse but are on the
925 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
926 beforeMargin = marginBeforeForChild(child);
927 afterMargin = marginAfterForChild(child);
928 }
929
930 // Resolve uncollapsing margins into their positive/negative buckets.
931 if (beforeMargin) {
932 if (beforeMargin > 0)
933 childBeforePositive = beforeMargin;
934 else
935 childBeforeNegative = -beforeMargin;
936 }
937 if (afterMargin) {
938 if (afterMargin > 0)
939 childAfterPositive = afterMargin;
940 else
941 childAfterNegative = -afterMargin;
942 }
943
944 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
945}
946
weinig@apple.com12840dc2013-10-22 23:59:08 +0000947LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000948{
949 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
950 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +0000951 bool childIsSelfCollapsing = child.isSelfCollapsingBlock();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000952
953 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
954 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
955
956 // Get the four margin values for the child and cache them.
957 const MarginValues childMargins = marginValuesForChild(child);
958
959 // Get our max pos and neg top margins.
960 LayoutUnit posTop = childMargins.positiveMarginBefore();
961 LayoutUnit negTop = childMargins.negativeMarginBefore();
962
963 // For self-collapsing blocks, collapse our bottom margins into our
964 // top to get new posTop and negTop values.
965 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000966 posTop = std::max(posTop, childMargins.positiveMarginAfter());
967 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000968 }
969
970 // See if the top margin is quirky. We only care if this child has
971 // margins that will collapse with us.
972 bool topQuirk = hasMarginBeforeQuirk(child);
973
974 if (marginInfo.canCollapseWithMarginBefore()) {
975 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
976 // This child is collapsing with the top of the
977 // block. If it has larger margin values, then we need to update
978 // our own maximal values.
979 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +0000980 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000981
982 // The minute any of the margins involved isn't a quirk, don't
983 // collapse it away, even if the margin is smaller (www.webreference.com
984 // has an example of this, a <dt> with 0.8em author-specified inside
985 // a <dl> inside a <td>.
986 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
987 setHasMarginBeforeQuirk(false);
988 marginInfo.setDeterminedMarginBeforeQuirk(true);
989 }
990
991 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
992 // We have no top margin and our top child has a quirky margin.
993 // We will pick up this quirky margin and pass it through.
994 // This deals with the <td><div><p> case.
995 // Don't do this for a block that split two inlines though. You do
996 // still apply margins in this case.
997 setHasMarginBeforeQuirk(true);
998 } else
999 // The before margin of the container will also discard all the margins it is collapsing with.
1000 setMustDiscardMarginBefore();
1001 }
1002
1003 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1004 if (childDiscardMarginBefore) {
1005 marginInfo.setDiscardMargin(true);
1006 marginInfo.clearMargin();
1007 }
1008
1009 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1010 marginInfo.setHasMarginBeforeQuirk(topQuirk);
1011
1012 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1013 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001014
1015 LayoutUnit clearanceForSelfCollapsingBlock;
1016 RenderObject* prev = child.previousSibling();
1017 // 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
1018 // 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
1019 // 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.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001020 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prev) && downcast<RenderBlockFlow>(*prev).isSelfCollapsingBlock()) {
1021 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prev).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001022 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1023 }
1024
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001025 if (childIsSelfCollapsing) {
1026 // 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.
1027 // Also, the child's top position equals the logical height of the container.
1028 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1029 // This child has no height. We need to compute our
1030 // position before we collapse the child's margins together,
1031 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001032 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1033 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001034 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1035
1036 // Now collapse the child's margins together, which means examining our
1037 // bottom margin values as well.
1038 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1039 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1040
1041 if (!marginInfo.canCollapseWithMarginBefore())
1042 // We need to make sure that the position of the self-collapsing block
1043 // is correct, since it could have overflowing content
1044 // that needs to be positioned correctly (e.g., a block that
1045 // had a specified height of 0 but that actually had subcontent).
1046 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1047 }
1048 } else {
1049 if (mustSeparateMarginBeforeForChild(child)) {
1050 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1051 // If we are at the before side of the block and we collapse, ignore the computed margin
1052 // and just add the child margin to the container height. This will correctly position
1053 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001054 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001055 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
1056 logicalTop = logicalHeight();
1057 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1058 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1059 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1060 // We're collapsing with a previous sibling's margins and not
1061 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001062 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001063 logicalTop = logicalHeight();
1064 }
1065
1066 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1067
1068 if (!marginInfo.discardMargin()) {
1069 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1070 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1071 } else
1072 marginInfo.clearMargin();
1073
1074 if (marginInfo.margin())
1075 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
1076 }
1077
1078 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1079 // collapsed into the page edge.
1080 LayoutState* layoutState = view().layoutState();
1081 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1082 && hasNextPage(beforeCollapseLogicalTop)) {
1083 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001084 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001085 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1086 }
1087
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001088 if (is<RenderBlockFlow>(prev) && !prev->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001089 // 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
1090 // any floats from the parent will now overhang.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001091 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prev);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001092 LayoutUnit oldLogicalHeight = logicalHeight();
1093 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001094 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001095 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001096 setLogicalHeight(oldLogicalHeight);
1097
1098 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1099 // 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
1100 // floats in the parent that overhang |child|'s new logical top.
1101 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
1102 if (logicalTopIntrudesIntoFloat && containsFloats() && !child.avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1103 child.setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001104 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001105
1106 return logicalTop;
1107}
1108
weinig@apple.com12840dc2013-10-22 23:59:08 +00001109LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001110{
1111 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1112 if (!heightIncrease)
1113 return yPos;
1114
weinig@apple.com12840dc2013-10-22 23:59:08 +00001115 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001116 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1117
1118 // For self-collapsing blocks that clear, they can still collapse their
1119 // margins with following siblings. Reset the current margins to represent
1120 // the self-collapsing block's margins only.
1121 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001122 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001123 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001124 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1125 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001126 } else
1127 marginInfo.clearMargin();
1128 marginInfo.setDiscardMargin(childDiscardMargin);
1129
1130 // CSS2.1 states:
1131 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1132 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1133 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1134 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1135 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001136 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001137 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1138 wouldCollapseMarginsWithParent = false;
1139 }
1140 if (wouldCollapseMarginsWithParent)
1141 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1142
robert@webkit.org97037ef2013-11-20 19:26:10 +00001143 // 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
1144 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1145 // 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
1146 // margins can collapse at the correct vertical position.
1147 // 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
1148 // (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],
1149 // i.e., clearance = [height of float] - margin-top".
1150 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001151 } else
1152 // Increase our height by the amount we had to clear.
1153 setLogicalHeight(logicalHeight() + heightIncrease);
1154
1155 if (marginInfo.canCollapseWithMarginBefore()) {
1156 // We can no longer collapse with the top of the block since a clear
1157 // occurred. The empty blocks collapse into the cleared block.
1158 // FIXME: This isn't quite correct. Need clarification for what to do
1159 // if the height the cleared block is offset by is smaller than the
1160 // margins involved.
1161 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1162 marginInfo.setAtBeforeSideOfBlock(false);
1163
1164 // 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 +00001165 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001166 }
1167
robert@webkit.org97037ef2013-11-20 19:26:10 +00001168 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001169}
1170
weinig@apple.com12840dc2013-10-22 23:59:08 +00001171void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001172{
1173 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1174 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1175 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001176 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001177 return;
1178
1179 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1180 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001181 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001182 positiveMarginBefore = 0;
1183 negativeMarginBefore = 0;
1184 discardMarginBefore = true;
1185 return;
1186 }
1187
1188 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001189 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1190 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001191
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001192 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001193 return;
1194
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001195 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001196 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001197 return;
1198
weinig@apple.com12840dc2013-10-22 23:59:08 +00001199 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001200 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1201 return;
1202
weinig@apple.com12840dc2013-10-22 23:59:08 +00001203 RenderBox* grandchildBox = childBlock.firstChildBox();
1204 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001205 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1206 break;
1207 }
1208
1209 // 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 +00001210 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001211 return;
1212
1213 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1214 if (grandchildBox->needsLayout()) {
1215 grandchildBox->computeAndSetBlockDirectionMargins(this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001216 if (is<RenderBlock>(*grandchildBox)) {
1217 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1218 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1219 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001220 }
1221 }
1222
1223 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001224 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001225}
1226
weinig@apple.com12840dc2013-10-22 23:59:08 +00001227LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001228{
1229 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1230 // relayout if there are intruding floats.
1231 LayoutUnit logicalTopEstimate = logicalHeight();
1232 if (!marginInfo.canCollapseWithMarginBefore()) {
1233 LayoutUnit positiveMarginBefore = 0;
1234 LayoutUnit negativeMarginBefore = 0;
1235 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001236 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001237 // Try to do a basic estimation of how the collapse is going to go.
1238 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1239 } else {
1240 // Use the cached collapsed margin values from a previous layout. Most of the time they
1241 // will be right.
1242 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001243 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1244 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001245 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1246 }
1247
1248 // Collapse the result with our current margins.
1249 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001250 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001251 }
1252
1253 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1254 // page.
1255 LayoutState* layoutState = view().layoutState();
1256 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1257 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001258 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001259
1260 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1261
1262 estimateWithoutPagination = logicalTopEstimate;
1263
1264 if (layoutState->isPaginated()) {
1265 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1266 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1267
1268 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1269 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1270
cdumez@apple.come9437792014-10-08 23:33:43 +00001271 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1272 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001273 }
1274
1275 return logicalTopEstimate;
1276}
1277
1278void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1279{
1280 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1281 // 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.
1282 // Don't update the max margin values because we won't need them anyway.
1283 if (marginInfo.discardMargin()) {
1284 setMustDiscardMarginAfter();
1285 return;
1286 }
1287
1288 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1289 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001290 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001291
1292 if (!marginInfo.hasMarginAfterQuirk())
1293 setHasMarginAfterQuirk(false);
1294
1295 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1296 // We have no bottom margin and our last child has a quirky margin.
1297 // We will pick up this quirky margin and pass it through.
1298 // This deals with the <td><div><p> case.
1299 setHasMarginAfterQuirk(true);
1300 }
1301}
1302
1303void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1304{
1305 marginInfo.setAtAfterSideOfBlock(true);
1306
robert@webkit.org97037ef2013-11-20 19:26:10 +00001307 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1308 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1309 // to perform now is at the child's margin-top - so adjust our height to that position.
1310 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001311 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1312 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001313
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001314 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001315 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1316 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1317 setLogicalHeight(logicalHeight() + marginInfo.margin());
1318
1319 // Now add in our bottom border/padding.
1320 setLogicalHeight(logicalHeight() + afterSide);
1321
1322 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1323 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001324 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001325
1326 // Update our bottom collapsed margin info.
1327 setCollapsedBottomMargin(marginInfo);
1328}
1329
1330void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1331{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001332 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001333 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001334 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001335 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001336 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001337
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001338 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1339 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001340}
1341
1342void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1343{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001344 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001345 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001346 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001347 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001348 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001349
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001350 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1351 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001352}
1353
1354void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1355{
akling@apple.com827be9c2013-10-29 02:58:43 +00001356 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001357 ASSERT(value);
1358 return;
1359 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001360
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001361 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001362 if (!value)
1363 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001364 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001365 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001366
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001367 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001368}
1369
1370void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1371{
akling@apple.com827be9c2013-10-29 02:58:43 +00001372 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001373 ASSERT(value);
1374 return;
1375 }
1376
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001377 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001378 if (!value)
1379 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001380 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001381 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001382
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001383 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001384}
1385
1386bool RenderBlockFlow::mustDiscardMarginBefore() const
1387{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001388 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001389}
1390
1391bool RenderBlockFlow::mustDiscardMarginAfter() const
1392{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001393 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001394}
1395
weinig@apple.com12840dc2013-10-22 23:59:08 +00001396bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001397{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001398 ASSERT(!child.selfNeedsLayout());
1399 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001400 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001401 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001402 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001403
1404 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1405 // In case the boxes are perpendicular we assume the property is not specified.
1406 return false;
1407}
1408
weinig@apple.com12840dc2013-10-22 23:59:08 +00001409bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001410{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001411 ASSERT(!child.selfNeedsLayout());
1412 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001413 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001414 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001415 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001416
1417 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1418 return false;
1419}
1420
weinig@apple.com12840dc2013-10-22 23:59:08 +00001421bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001422{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001423 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001424 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001425 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001426 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001427 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001428 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001429
1430 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1431 return false;
1432}
1433
weinig@apple.com12840dc2013-10-22 23:59:08 +00001434bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001435{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001436 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001437 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001438 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001439 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001440 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001441 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001442
1443 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1444 return false;
1445}
1446
weinig@apple.com12840dc2013-10-22 23:59:08 +00001447static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001448{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001449 RenderBlock* curr = child.containingBlock();
1450 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001451 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001452 return true;
1453 if (curr->isFloatingOrOutOfFlowPositioned())
1454 return false;
1455 curr = curr->containingBlock();
1456 }
1457 return true;
1458}
1459
weinig@apple.com12840dc2013-10-22 23:59:08 +00001460LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001461{
1462 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001463 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001464 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001465 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001466 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 +00001467 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001468 bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
1469 || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001470 || (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001471 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001472 if (checkColumnBreaks) {
1473 if (isInsideMulticolFlowThread)
1474 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001475 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001476 if (checkRegionBreaks) {
1477 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001478 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001479 return logicalOffset + offsetBreakAdjustment;
1480 }
1481 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1482 }
1483 return logicalOffset;
1484}
1485
weinig@apple.com12840dc2013-10-22 23:59:08 +00001486LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001487{
1488 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001489 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001490 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001491 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001492 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 +00001493 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001494 bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
1495 || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001496 || (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001497 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1498 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1499
1500 // So our margin doesn't participate in the next collapsing steps.
1501 marginInfo.clearMargin();
1502
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001503 if (checkColumnBreaks) {
1504 if (isInsideMulticolFlowThread)
1505 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001506 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001507 if (checkRegionBreaks) {
1508 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001509 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001510 return logicalOffset + marginOffset + offsetBreakAdjustment;
1511 }
1512 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1513 }
1514 return logicalOffset;
1515}
1516
weinig@apple.com12840dc2013-10-22 23:59:08 +00001517LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001518{
cdumez@apple.come9437792014-10-08 23:33:43 +00001519 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001520
1521 if (estimateWithoutPagination != logicalTopAfterClear) {
1522 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1523 // position.
1524 setLogicalHeight(logicalTopAfterClear);
1525 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1526
weinig@apple.com12840dc2013-10-22 23:59:08 +00001527 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001528 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1529 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001530 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001531 }
1532
1533 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001534 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001535 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001536 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001537 }
1538
1539 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001540 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001541 }
1542
1543 LayoutUnit oldTop = logicalTopAfterClear;
1544
1545 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1546 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1547
1548 if (pageLogicalHeightForOffset(result)) {
1549 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001550 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001551 if (spaceShortage > 0) {
1552 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1553 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1554 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1555 // This should be improved, though, because here we just pretend that the child is
1556 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1557 // where there's no child content, border or padding. In other words, we risk stretching more
1558 // than necessary.
1559 setPageBreak(result, spaceShortage);
1560 }
1561 }
1562
1563 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1564 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1565 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1566
1567 LayoutUnit paginationStrut = 0;
1568 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1569 if (unsplittableAdjustmentDelta)
1570 paginationStrut = unsplittableAdjustmentDelta;
1571 else if (childRenderBlock && childRenderBlock->paginationStrut())
1572 paginationStrut = childRenderBlock->paginationStrut();
1573
1574 if (paginationStrut) {
1575 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1576 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1577 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1578 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1579 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1580 // and pushes to the next page anyway, so not too concerned about it.
1581 setPaginationStrut(result + paginationStrut);
1582 if (childRenderBlock)
1583 childRenderBlock->setPaginationStrut(0);
1584 } else
1585 result += paginationStrut;
1586 }
1587
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001588 // 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 +00001589 setLogicalHeight(logicalHeight() + (result - oldTop));
1590
1591 // Return the final adjusted logical top.
1592 return result;
1593}
1594
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001595static inline LayoutUnit calculateMinimumPageHeight(RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001596{
1597 // We may require a certain minimum number of lines per page in order to satisfy
1598 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001599 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001600 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001601 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001602 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1603 line = line->prevRootBox();
1604
1605 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1606 // adjustLinePositionForPagination() for more details.
1607 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001608 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001609 }
1610 return lineBottom - lineTop;
1611}
1612
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001613static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1614{
bfulgham@apple.com62729772015-04-29 02:26:07 +00001615 const auto& renderer = lineBox.renderer();
1616
1617 if (!renderer.document().settings())
1618 return false;
1619
1620 if (!renderer.document().settings()->appleMailPaginationQuirkEnabled())
1621 return false;
1622
1623 if (renderer.element() && renderer.element()->idForStyleResolution() == AtomicString("messageContentContainer", AtomicString::ConstructFromLiteral))
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001624 return true;
1625
1626 return false;
1627}
1628
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001629void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001630{
1631 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1632 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1633 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1634 // of the first column.
1635 //
1636 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1637 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1638 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1639 // for overflow to occur), and then cache visible overflow for each column rect.
1640 //
1641 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1642 // content that paints in a previous column (and content that paints in the following column).
1643 //
1644 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1645 // at least make positive leading work in typical cases.
1646 //
1647 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1648 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1649 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001650 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001651 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001652 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1653 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001654 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001655 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001656 logicalOffset += delta;
1657 lineBox->setPaginationStrut(0);
1658 lineBox->setIsFirstAfterPageBreak(false);
1659 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1660 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1661 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1662 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001663 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001664 // 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.
1665 // 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 +00001666 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001667 }
1668
1669 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1670 // 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
1671 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1672 // 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
1673 // top of the page.
1674 // 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
1675 // this will be a real-world issue. For now we don't try to deal with this problem.
1676 logicalOffset = intMaxForLayoutUnit;
1677 logicalBottom = intMinForLayoutUnit;
1678 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1679 lineHeight = logicalBottom - logicalOffset;
1680 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1681 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1682 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1683 }
1684
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001685 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001686 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001687
1688 int lineIndex = lineCount(lineBox);
1689 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001690 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001691 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001692 setDidBreakAtLineToAvoidWidow();
1693 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001694 // If we have a non-uniform page height, then we have to shift further possibly.
1695 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1696 return;
1697 if (lineHeight > pageLogicalHeight) {
1698 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001699 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001700 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001701 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1702 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001703 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001704 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1705 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001706 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001707 && !isOutOfFlowPositioned() && !isTableCell()) {
1708 auto firstRootBox = this->firstRootBox();
1709 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1710 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001711 if (needsAppleMailPaginationQuirk(*lineBox))
1712 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001713 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1714 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001715 delta += remainingLogicalHeight;
1716 lineBox->setPaginationStrut(remainingLogicalHeight);
1717 lineBox->setIsFirstAfterPageBreak(true);
1718 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001719 } else if (remainingLogicalHeight == pageLogicalHeight) {
1720 // We're at the very top of a page or column.
1721 if (lineBox != firstRootBox())
1722 lineBox->setIsFirstAfterPageBreak(true);
1723 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1724 setPageBreak(logicalOffset, lineHeight);
1725 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001726}
1727
1728void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1729{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001730 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001731 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1732 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001733}
1734
abucur@adobe.comfc497132013-10-04 08:49:21 +00001735void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1736{
1737 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001738 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001739 return;
1740
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001741 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001742}
1743
1744void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1745{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001746 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001747 return;
1748
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001749 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001750}
1751
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001752void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1753{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001754 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001755 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001756 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001757
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001758 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001759}
1760
1761bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1762{
1763 if (!shouldBreakAtLineToAvoidWidow())
1764 return false;
1765
1766 statePusher.pop();
1767 setEverHadLayout(true);
1768 layoutBlock(false);
1769 return true;
1770}
1771
weinig@apple.com31324fd2013-10-28 19:22:51 +00001772bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1773{
1774 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1775
1776 RenderFlowThread* flowThread = flowThreadContainingBlock();
1777 if (!flowThread)
1778 return true; // Printing and multi-column both make new pages to accommodate content.
1779
1780 // See if we're in the last region.
1781 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001782 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001783 if (!region)
1784 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001785
weinig@apple.com31324fd2013-10-28 19:22:51 +00001786 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001787 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001788 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001789
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001790 RenderRegion* startRegion = nullptr;
1791 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001792 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001793 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001794}
1795
1796LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1797{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001798 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001799 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001800
1801 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001802 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1803 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1804 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1805 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1806 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1807 || !hasNextPage(logicalOffset))
1808 return logicalOffset;
1809 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1810 if (remainingLogicalHeight < childLogicalHeight) {
1811 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1812 return logicalOffset;
1813 return logicalOffset + remainingLogicalHeight;
1814 }
1815 return logicalOffset;
1816}
1817
1818bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1819{
1820 bool checkRegion = false;
1821 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1822 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1823 if (minimumLogicalHeight <= pageLogicalHeight)
1824 return true;
1825 if (!hasNextPage(logicalOffset + adjustment))
1826 return false;
1827 adjustment += pageLogicalHeight;
1828 checkRegion = true;
1829 }
1830 return !checkRegion;
1831}
1832
1833void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1834{
1835 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1836 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1837}
1838
1839void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1840{
1841 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1842 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001843}
1844
1845LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1846{
1847 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1848 if (!pageLogicalHeight)
1849 return logicalOffset;
1850
1851 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1852 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1853 if (pageBoundaryRule == ExcludePageBoundary)
1854 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1855 return logicalOffset + remainingLogicalHeight;
1856}
1857
1858LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1859{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001860 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1861 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1862 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1863 if (!pageLogicalHeight)
1864 return 0;
1865
weinig@apple.com31324fd2013-10-28 19:22:51 +00001866 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1867 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1868
1869 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1870 RenderFlowThread* flowThread = flowThreadContainingBlock();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001871 if (!flowThread)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001872 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001873 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001874}
1875
1876LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1877{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001878 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1879 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1880 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1881 if (!pageLogicalHeight)
1882 return 0;
1883
1884 // Now check for a flow thread.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001885 RenderFlowThread* flowThread = flowThreadContainingBlock();
1886 if (!flowThread)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001887 return pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001888 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1889}
1890
1891LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1892{
1893 offset += offsetFromLogicalTopOfFirstPage();
1894
1895 RenderFlowThread* flowThread = flowThreadContainingBlock();
1896 if (!flowThread) {
1897 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1898 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1899 if (pageBoundaryRule == IncludePageBoundary) {
1900 // If includeBoundaryPoint is true the line exactly on the top edge of a
1901 // column will act as being part of the previous column.
1902 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1903 }
1904 return remainingHeight;
1905 }
1906
1907 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1908}
1909
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001910LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1911{
1912 // This method is required because regions do not fragment monolithic elements but instead
1913 // they let them overflow the region they flow in. This behaviour is different from the
1914 // multicol/printing implementations, which have not yet been updated to correctly handle
1915 // monolithic elements.
1916 // As a result, for the moment, this method will only be used for regions, the multicol and
1917 // printing implementations will stick to the existing behaviour until their fragmentation
1918 // implementation is updated to match the regions implementation.
1919 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1920 return logicalHeightForChild(child);
1921
1922 // For unsplittable elements, this method will just return the height of the element that
1923 // fits into the current region, without the height of the part that overflows the region.
1924 // This is done for all regions, except the last one because in that case, the logical
1925 // height of the flow thread needs to also
1926 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1927 return logicalHeightForChild(child);
1928
1929 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1930 // the entire unsplittable child because any following children will not be moved to the next page
1931 // so they will need to be laid out below the current unsplittable child.
1932 LayoutUnit childLogicalTop = logicalTopForChild(child);
1933 if (!hasNextPage(childLogicalTop))
1934 return logicalHeightForChild(child);
1935
1936 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1937 return std::min(child.logicalHeight(), remainingLogicalHeight);
1938}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001939
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001940void RenderBlockFlow::layoutLineGridBox()
1941{
akling@apple.com827be9c2013-10-29 02:58:43 +00001942 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001943 setLineGridBox(0);
1944 return;
1945 }
1946
1947 setLineGridBox(0);
1948
akling@apple.com1aa97b02013-10-31 21:59:49 +00001949 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001950 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1951 lineGridBox->setConstructed();
1952 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1953 VerticalPositionCache verticalPositionCache;
1954 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1955
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00001956 setLineGridBox(WTF::move(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001957
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001958 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1959 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1960 // to this grid.
1961}
1962
weinig@apple.com12840dc2013-10-22 23:59:08 +00001963bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001964{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001965 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001966}
1967
1968void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1969{
1970 RenderBlock::styleDidChange(diff, oldStyle);
1971
1972 // After our style changed, if we lose our ability to propagate floats into next sibling
1973 // blocks, then we need to find the top most parent containing that overhanging float and
1974 // then mark its descendants with floats for layout and clear all floats from its next
1975 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1976 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1977 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
1978 RenderBlockFlow* parentBlock = this;
1979 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001980
weinig@apple.comc77041e2013-12-14 18:05:45 +00001981 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
1982 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00001983 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00001984 if (ancestor.hasOverhangingFloats()) {
akling@apple.comf3028052013-11-04 08:46:06 +00001985 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
1986 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00001987 if (ancestor.hasOverhangingFloat(renderer)) {
1988 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00001989 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001990 }
1991 }
1992 }
1993 }
1994
1995 parentBlock->markAllDescendantsWithFloatsForLayout();
1996 parentBlock->markSiblingsWithFloatsForLayout();
1997 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00001998
akling@apple.com8f40c5b2013-10-27 22:54:07 +00001999 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00002000 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00002001
antti@apple.com9e891c82014-05-22 06:12:34 +00002002 if (diff >= StyleDifferenceRepaint) {
2003 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2004 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2005 invalidateLineLayoutPath();
2006 }
2007
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002008 if (multiColumnFlowThread())
2009 updateStylesForColumnChildren();
2010}
2011
2012void RenderBlockFlow::updateStylesForColumnChildren()
2013{
2014 for (auto child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
2015 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002016}
2017
akling@apple.combdae43242013-10-25 12:00:20 +00002018void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002019{
akling@apple.com827be9c2013-10-29 02:58:43 +00002020 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002021 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2022
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002023 if (oldStyle) {
2024 EPosition oldPosition = oldStyle->position();
2025 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002026
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002027 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2028 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2029 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002030 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002031 }
2032
2033 RenderBlock::styleWillChange(diff, newStyle);
2034}
2035
antti@apple.coma2c7f242013-10-22 22:37:25 +00002036void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002037{
2038 if (containsFloats())
2039 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002040
antti@apple.comfea51992013-10-28 13:39:23 +00002041 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002042 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002043 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002044 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002045 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002046
antti@apple.coma2c7f242013-10-22 22:37:25 +00002047 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002048}
2049
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002050void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002051{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002052 // When a portion of the render tree is being detached, anonymous blocks
2053 // will be combined as their children are deleted. In this process, the
2054 // anonymous block later in the tree is merged into the one preceeding it.
2055 // It can happen that the later block (this) contains floats that the
2056 // previous block (toBlockFlow) did not contain, and thus are not in the
2057 // floating objects list for toBlockFlow. This can result in toBlockFlow
2058 // containing floats that are not in it's floating objects list, but are in
2059 // the floating objects lists of siblings and parents. This can cause
2060 // problems when the float itself is deleted, since the deletion code
2061 // assumes that if a float is not in it's containing block's floating
2062 // objects list, it isn't in any floating objects list. In order to
2063 // preserve this condition (removing it has serious performance
2064 // implications), we need to copy the floating objects from the old block
2065 // (this) to the new block (toBlockFlow). The float's metrics will likely
2066 // all be wrong, but since toBlockFlow is already marked for layout, this
2067 // will get fixed before anything gets displayed.
2068 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2069 if (m_floatingObjects) {
2070 if (!toBlockFlow->m_floatingObjects)
2071 toBlockFlow->createFloatingObjects();
2072
2073 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2074 auto end = fromFloatingObjectSet.end();
2075
2076 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2077 FloatingObject* floatingObject = it->get();
2078
2079 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002080 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002081 continue;
2082
2083 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2084 }
2085 }
2086}
2087
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002088void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002089{
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002090 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2091 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2092 moveFloatsTo(&toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002093}
2094
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002095void RenderBlockFlow::addOverflowFromFloats()
2096{
2097 if (!m_floatingObjects)
2098 return;
2099
2100 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2101 auto end = floatingObjectSet.end();
2102 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2103 FloatingObject* r = it->get();
2104 if (r->isDescendant())
2105 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
2106 }
2107}
2108
2109void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2110{
2111 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2112
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002113 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002114 addOverflowFromFloats();
2115}
2116
2117void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2118{
2119 // Repaint any overhanging floats (if we know we're the one to paint them).
2120 // Otherwise, bail out.
2121 if (!hasOverhangingFloats())
2122 return;
2123
2124 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2125 // in this block. Better yet would be to push extra state for the containers of other floats.
2126 LayoutStateDisabler layoutStateDisabler(&view());
2127 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2128 auto end = floatingObjectSet.end();
2129 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2130 FloatingObject* floatingObject = it->get();
2131 // Only repaint the object if it is overhanging, is not in its own layer, and
2132 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2133 // condition is replaced with being a descendant of us.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002134 if (logicalBottomForFloat(floatingObject) > logicalHeight()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002135 && !floatingObject->renderer().hasSelfPaintingLayer()
2136 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
2137 floatingObject->renderer().repaint();
2138 floatingObject->renderer().repaintOverhangingFloats(false);
2139 }
2140 }
2141}
2142
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002143void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002144{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002145 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002146
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002147 if (!multiColumnFlowThread() || paintInfo.context->paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002148 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002149
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002150 // Iterate over our children and paint the column rules as needed.
2151 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2152 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2153 columnSet.paintColumnRules(paintInfo, childPoint);
2154 }
2155}
2156
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002157void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2158{
2159 if (!m_floatingObjects)
2160 return;
2161
2162 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2163 auto end = floatingObjectSet.end();
2164 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2165 FloatingObject* r = it->get();
2166 // Only paint the object if our m_shouldPaint flag is set.
2167 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
2168 PaintInfo currentPaintInfo(paintInfo);
2169 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2170 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
2171 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2172 r->renderer().paint(currentPaintInfo, childPoint);
2173 if (!preservePhase) {
2174 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2175 r->renderer().paint(currentPaintInfo, childPoint);
2176 currentPaintInfo.phase = PaintPhaseFloat;
2177 r->renderer().paint(currentPaintInfo, childPoint);
2178 currentPaintInfo.phase = PaintPhaseForeground;
2179 r->renderer().paint(currentPaintInfo, childPoint);
2180 currentPaintInfo.phase = PaintPhaseOutline;
2181 r->renderer().paint(currentPaintInfo, childPoint);
2182 }
2183 }
2184 }
2185}
2186
weinig@apple.com12840dc2013-10-22 23:59:08 +00002187void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002188{
2189 if (m_floatingObjects) {
2190 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2191 auto end = floatingObjectSet.end();
2192 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2193 FloatingObject* floatingObject = it->get();
2194 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2195 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
2196 floatingObject->renderer().width(), floatingObject->renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002197 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002198 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
zalan@apple.com376339c2014-08-28 04:24:31 +00002199 paintInfo->context->clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002200 }
2201 }
2202}
2203
2204void RenderBlockFlow::createFloatingObjects()
2205{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002206 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002207}
2208
2209void RenderBlockFlow::removeFloatingObjects()
2210{
2211 if (!m_floatingObjects)
2212 return;
2213
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002214 markSiblingsWithFloatsForLayout();
2215
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002216 m_floatingObjects->clear();
2217}
2218
weinig@apple.com12840dc2013-10-22 23:59:08 +00002219FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002220{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002221 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002222
2223 // Create the list of special objects if we don't aleady have one
2224 if (!m_floatingObjects)
2225 createFloatingObjects();
2226 else {
2227 // Don't insert the floatingObject again if it's already in the list
2228 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002229 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002230 if (it != floatingObjectSet.end())
2231 return it->get();
2232 }
2233
2234 // Create the special floatingObject entry & append it to the list
2235
weinig@apple.com12840dc2013-10-22 23:59:08 +00002236 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002237
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002238 // 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 +00002239 bool isChildRenderBlock = floatBox.isRenderBlock();
2240 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2241 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002242
2243 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002244 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2245 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002246 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002247 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2248 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002249 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002250 floatBox.updateLogicalWidth();
2251 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002252 }
2253
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002254 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002255
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00002256 return m_floatingObjects->add(WTF::move(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002257}
2258
weinig@apple.com12840dc2013-10-22 23:59:08 +00002259void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002260{
2261 if (m_floatingObjects) {
2262 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002263 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002264 if (it != floatingObjectSet.end()) {
2265 FloatingObject* floatingObject = it->get();
2266 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002267 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2268 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002269
2270 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2271 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2272 logicalBottom = LayoutUnit::max();
2273 else {
2274 // Special-case zero- and less-than-zero-height floats: those don't touch
2275 // the line that they're on, but it still needs to be dirtied. This is
2276 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002277 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002278 }
2279 if (floatingObject->originatingLine()) {
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002280 floatingObject->originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002281 if (!selfNeedsLayout()) {
2282 ASSERT(&floatingObject->originatingLine()->renderer() == this);
2283 floatingObject->originatingLine()->markDirty();
2284 }
2285#if !ASSERT_DISABLED
2286 floatingObject->setOriginatingLine(0);
2287#endif
2288 }
2289 markLinesDirtyInBlockRange(0, logicalBottom);
2290 }
2291 m_floatingObjects->remove(floatingObject);
2292 }
2293 }
2294}
2295
2296void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2297{
2298 if (!containsFloats())
2299 return;
2300
2301 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2302 FloatingObject* curr = floatingObjectSet.last().get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002303 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002304 m_floatingObjects->remove(curr);
2305 if (floatingObjectSet.isEmpty())
2306 break;
2307 curr = floatingObjectSet.last().get();
2308 }
2309}
2310
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002311LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2312{
2313 LayoutUnit offset = fixedOffset;
2314 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2315 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2316 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2317}
2318
2319LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2320{
2321 LayoutUnit offset = fixedOffset;
2322 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2323 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2324 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2325}
2326
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002327LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002328{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002329 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002330 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002331 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002332
andersca@apple.com86298632013-11-10 19:32:33 +00002333 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002334
2335 LayoutUnit floatLogicalLeft;
2336
2337 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002338 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2339
2340 if (isInitialLetter) {
2341 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2342 if (letterClearance > 0) {
2343 logicalTopOffset += letterClearance;
2344 setLogicalHeight(logicalHeight() + letterClearance);
2345 }
2346 }
2347
akling@apple.com827be9c2013-10-29 02:58:43 +00002348 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002349 LayoutUnit heightRemainingLeft = 1;
2350 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002351 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2352 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002353 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002354 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002355 if (insideFlowThread) {
2356 // Have to re-evaluate all of our offsets, since they may have changed.
2357 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2358 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002359 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002360 }
2361 }
andersca@apple.com86298632013-11-10 19:32:33 +00002362 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002363 } else {
2364 LayoutUnit heightRemainingLeft = 1;
2365 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002366 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2367 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002368 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002369 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002370 if (insideFlowThread) {
2371 // Have to re-evaluate all of our offsets, since they may have changed.
2372 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2373 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002374 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002375 }
2376 }
2377 // Use the original width of the float here, since the local variable
2378 // |floatLogicalWidth| was capped to the available line width. See
2379 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002380 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002381 }
2382
hyatt@apple.com87515262014-09-04 21:20:12 +00002383 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002384 const RenderStyle& style = firstLineStyle();
2385 const FontMetrics& fontMetrics = style.fontMetrics();
2386 if (fontMetrics.hasCapHeight()) {
2387 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2388 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2389
2390 // Make an adjustment to align with the cap height of a theoretical block line.
2391 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2392 logicalTopOffset += adjustment;
2393
2394 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2395 // positive for raised and negative for sunken).
2396 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2397
2398 // 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.
2399 if (dropHeightDelta < 0) {
2400 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2401 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2402 }
2403
2404 // 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
2405 // empty lines beside the first letter.
2406 if (dropHeightDelta > 0)
2407 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2408 }
2409 }
2410
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002411 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2412}
2413
2414bool RenderBlockFlow::positionNewFloats()
2415{
2416 if (!m_floatingObjects)
2417 return false;
2418
2419 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2420 if (floatingObjectSet.isEmpty())
2421 return false;
2422
2423 // If all floats have already been positioned, then we have no work to do.
2424 if (floatingObjectSet.last()->isPlaced())
2425 return false;
2426
2427 // Move backwards through our floating object list until we find a float that has
2428 // already been positioned. Then we'll be able to move forward, positioning all of
2429 // the new floats that need it.
2430 auto it = floatingObjectSet.end();
2431 --it; // Go to last item.
2432 auto begin = floatingObjectSet.begin();
2433 FloatingObject* lastPlacedFloatingObject = 0;
2434 while (it != begin) {
2435 --it;
2436 if ((*it)->isPlaced()) {
2437 lastPlacedFloatingObject = it->get();
2438 ++it;
2439 break;
2440 }
2441 }
2442
2443 LayoutUnit logicalTop = logicalHeight();
2444
2445 // The float cannot start above the top position of the last positioned float.
2446 if (lastPlacedFloatingObject)
andersca@apple.com86298632013-11-10 19:32:33 +00002447 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002448
2449 auto end = floatingObjectSet.end();
2450 // Now walk through the set of unpositioned floats and place them.
2451 for (; it != end; ++it) {
2452 FloatingObject* floatingObject = it->get();
2453 // The containing block is responsible for positioning floats, so if we have floats in our
2454 // list that come from somewhere else, do not attempt to position them.
2455 if (floatingObject->renderer().containingBlock() != this)
2456 continue;
2457
weinig@apple.com12840dc2013-10-22 23:59:08 +00002458 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002459
akling@apple.com827be9c2013-10-29 02:58:43 +00002460 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002461
weinig@apple.com12840dc2013-10-22 23:59:08 +00002462 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002463
akling@apple.com827be9c2013-10-29 02:58:43 +00002464 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002465 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002466 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002467 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002468
2469 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2470
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002471 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002472
2473 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2474 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2475
2476 estimateRegionRangeForBoxChild(childBox);
2477
hyatt@apple.comccad3742015-02-04 21:39:00 +00002478 childBox.markForPaginationRelayoutIfNeeded();
2479 childBox.layoutIfNeeded();
2480
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002481 LayoutState* layoutState = view().layoutState();
2482 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002483 if (isPaginated) {
2484 // If we are unsplittable and don't fit, then we need to move down.
2485 // We include our margins as part of the unsplittable area.
2486 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2487
2488 // See if we have a pagination strut that is making us move down further.
2489 // Note that an unsplittable child can't also have a pagination strut, so this is
2490 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002491 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002492 if (childBlock && childBlock->paginationStrut()) {
2493 newLogicalTop += childBlock->paginationStrut();
2494 childBlock->setPaginationStrut(0);
2495 }
2496
2497 if (newLogicalTop != floatLogicalLocation.y()) {
2498 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
2499
2500 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002501 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002502
2503 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2504 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2505
2506 if (childBlock)
2507 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002508 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002509 }
2510
2511 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002512 childBox.setNeedsLayout(MarkOnlyThis);
2513 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002514 }
2515 }
2516
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002517 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002518
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002519 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002520
2521 m_floatingObjects->addPlacedObject(floatingObject);
2522
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002523#if ENABLE(CSS_SHAPES)
2524 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002525 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002526#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002527 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002528 if (childBox.checkForRepaintDuringLayout())
2529 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002530 }
2531 return true;
2532}
2533
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002534void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002535{
2536 positionNewFloats();
2537 // set y position
2538 LayoutUnit newY = 0;
2539 switch (clear) {
2540 case CLEFT:
2541 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2542 break;
2543 case CRIGHT:
2544 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2545 break;
2546 case CBOTH:
2547 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002548 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002549 default:
2550 break;
2551 }
2552 if (height() < newY)
2553 setLogicalHeight(newY);
2554}
2555
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002556LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002557{
2558 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002559 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002560
2561 return fixedOffset;
2562}
2563
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002564LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002565{
2566 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002567 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002568
2569 return fixedOffset;
2570}
2571
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002572LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002573{
2574 if (!m_floatingObjects)
2575 return logicalHeight;
2576
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002577 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2578}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002579
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002580LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2581{
2582 if (!m_floatingObjects)
2583 return logicalHeight;
2584
2585 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002586}
2587
2588LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2589{
2590 if (!m_floatingObjects)
2591 return 0;
2592 LayoutUnit lowestFloatBottom = 0;
2593 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2594 auto end = floatingObjectSet.end();
2595 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2596 FloatingObject* floatingObject = it->get();
2597 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
andersca@apple.com86298632013-11-10 19:32:33 +00002598 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002599 }
2600 return lowestFloatBottom;
2601}
2602
hyatt@apple.com87515262014-09-04 21:20:12 +00002603LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2604{
2605 if (!m_floatingObjects)
2606 return 0;
2607 LayoutUnit lowestFloatBottom = 0;
2608 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2609 auto end = floatingObjectSet.end();
2610 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2611 FloatingObject* floatingObject = it->get();
2612 if (floatingObject->isPlaced() && floatingObject->renderer().style().styleType() == FIRST_LETTER && floatingObject->renderer().style().initialLetterDrop() > 0)
2613 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2614 }
2615 return lowestFloatBottom;
2616}
2617
weinig@apple.com12840dc2013-10-22 23:59:08 +00002618LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002619{
2620 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002621 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002622 return 0;
2623
weinig@apple.com12840dc2013-10-22 23:59:08 +00002624 LayoutUnit childLogicalTop = child.logicalTop();
2625 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002626 LayoutUnit lowestFloatLogicalBottom = 0;
2627
2628 // Floats that will remain the child's responsibility to paint should factor into its
2629 // overflow.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002630 auto childEnd = child.m_floatingObjects->set().end();
2631 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002632 FloatingObject* floatingObject = childIt->get();
andersca@apple.com86298632013-11-10 19:32:33 +00002633 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002634 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002635 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002636
2637 if (logicalBottom > logicalHeight()) {
2638 // If the object is not in the list, we add it now.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002639 if (!containsFloat(floatingObject->renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002640 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2641 bool shouldPaint = false;
2642
2643 // The nearest enclosing layer always paints the float (so that zindex and stacking
2644 // behaves properly). We always want to propagate the desire to paint the float as
2645 // far out as we can, to the outermost block that overlaps the float, stopping only
2646 // if we hit a self-painting layer boundary.
2647 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2648 floatingObject->setShouldPaint(false);
2649 shouldPaint = true;
2650 }
2651 // We create the floating object list lazily.
2652 if (!m_floatingObjects)
2653 createFloatingObjects();
2654
2655 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2656 }
2657 } else {
2658 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
weinig@apple.com12840dc2013-10-22 23:59:08 +00002659 && floatingObject->renderer().isDescendantOf(&child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002660 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2661 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2662 // layer.
2663 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2664 // it should paint.
2665 floatingObject->setShouldPaint(true);
2666 }
2667
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002668 // Since the float doesn't overhang, it didn't get put into our list. We need to add its overflow in to the child now.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002669 if (floatingObject->isDescendant())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002670 child.addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002671 }
2672 }
2673 return lowestFloatLogicalBottom;
2674}
2675
weinig@apple.com12840dc2013-10-22 23:59:08 +00002676bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002677{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002678 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002679 return false;
2680
2681 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002682 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002683 if (it == floatingObjectSet.end())
2684 return false;
2685
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002686 return logicalBottomForFloat(it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002687}
2688
hyatt@apple.com21c60802015-04-01 18:10:32 +00002689void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002690{
2691 ASSERT(!avoidsFloats());
2692
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002693 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2694 if (createsNewFormattingContext())
2695 return;
2696
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002697 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2698 if (!prev->m_floatingObjects)
2699 return;
2700
2701 logicalLeftOffset += marginLogicalLeft();
2702
2703 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2704 auto prevEnd = prevSet.end();
2705 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2706 FloatingObject* floatingObject = prevIt->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002707 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002708 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2709 // We create the floating object list lazily.
2710 if (!m_floatingObjects)
2711 createFloatingObjects();
2712
2713 // Applying the child's margin makes no sense in the case where the child was passed in.
2714 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2715 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2716 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2717 // will get applied twice.
2718 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002719 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2720 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002721
2722 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2723 }
2724 }
2725 }
2726}
2727
2728void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2729{
2730 if (!everHadLayout() && !containsFloats())
2731 return;
2732
2733 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2734 setChildNeedsLayout(markParents);
2735
2736 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002737 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002738
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002739 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002740 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2741 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2742 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002743 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002744 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2745 block.setChildNeedsLayout(markParents);
2746 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002747 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002748 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002749 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2750 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002751 }
2752}
2753
2754void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2755{
2756 if (!m_floatingObjects)
2757 return;
2758
2759 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2760 auto end = floatingObjectSet.end();
2761
2762 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
cdumez@apple.come9437792014-10-08 23:33:43 +00002763 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned() || downcast<RenderBlockFlow>(*next).avoidsFloats())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002764 continue;
2765
cdumez@apple.come9437792014-10-08 23:33:43 +00002766 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002767 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002768 RenderBox& floatingBox = (*it)->renderer();
2769 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002770 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002771 if (nextBlock.containsFloat(floatingBox))
2772 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002773 }
2774 }
2775}
2776
weinig@apple.com31324fd2013-10-28 19:22:51 +00002777LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2778{
akling@apple.com827be9c2013-10-29 02:58:43 +00002779 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002780 return point;
2781
2782 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2783 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2784 // case.
2785 if (isHorizontalWritingMode())
2786 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2787 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2788}
2789
weinig@apple.com12840dc2013-10-22 23:59:08 +00002790LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002791{
2792 // There is no need to compute clearance if we have no floats.
2793 if (!containsFloats())
2794 return 0;
2795
2796 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002797 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002798 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002799 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002800 case CNONE:
2801 break;
2802 case CLEFT:
2803 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2804 break;
2805 case CRIGHT:
2806 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2807 break;
2808 case CBOTH:
2809 logicalBottom = lowestFloatLogicalBottom();
2810 break;
2811 }
2812
2813 // 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 +00002814 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002815 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002816 LayoutUnit newLogicalTop = logicalTop;
2817 while (true) {
2818 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2819 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2820 return newLogicalTop - logicalTop;
2821
2822 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002823 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002824 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2825
2826 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002827 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2828 LayoutUnit childOldMarginLeft = child.marginLeft();
2829 LayoutUnit childOldMarginRight = child.marginRight();
2830 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002831
weinig@apple.com12840dc2013-10-22 23:59:08 +00002832 child.setLogicalTop(newLogicalTop);
2833 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002834 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002835 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002836 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2837
weinig@apple.com12840dc2013-10-22 23:59:08 +00002838 child.setLogicalTop(childOldLogicalTop);
2839 child.setLogicalWidth(childOldLogicalWidth);
2840 child.setMarginLeft(childOldMarginLeft);
2841 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002842
2843 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2844 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2845 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2846 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2847 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002848 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002849 return newLogicalTop - logicalTop;
2850 }
2851
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002852 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002853 ASSERT(newLogicalTop >= logicalTop);
2854 if (newLogicalTop < logicalTop)
2855 break;
2856 }
2857 ASSERT_NOT_REACHED();
2858 }
2859 return result;
2860}
2861
2862bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2863{
2864 if (!m_floatingObjects)
2865 return false;
2866
2867 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002868 if (is<RenderView>(*this))
2869 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002870
2871 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2872 auto begin = floatingObjectSet.begin();
2873 for (auto it = floatingObjectSet.end(); it != begin;) {
2874 --it;
2875 FloatingObject* floatingObject = it->get();
2876 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2877 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2878 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2879 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2880 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2881 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2882 return true;
2883 }
2884 }
2885 }
2886
2887 return false;
2888}
2889
weinig@apple.com611b9292013-10-20 22:57:54 +00002890bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2891{
2892 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002893
darin@apple.come1be6ca2014-04-28 04:19:10 +00002894 if (auto simpleLineLayout = this->simpleLineLayout())
2895 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002896
weinig@apple.com611b9292013-10-20 22:57:54 +00002897 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2898}
2899
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002900void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2901{
akling@apple.com827be9c2013-10-29 02:58:43 +00002902 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002903 return;
2904
2905 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2906 // for either overflow or translations via relative positioning.
2907 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002908 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2909
weinig@apple.com611b9292013-10-20 22:57:54 +00002910 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
2911 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002912 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002913 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002914 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002915 }
2916 } else {
2917 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2918 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002919 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2920 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002921 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002922 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002923 left = std::min(left, x + obj->x());
2924 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002925 }
2926 }
2927 }
2928 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002929
2930 if (m_floatingObjects) {
2931 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2932 auto end = floatingObjectSet.end();
2933 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2934 FloatingObject* r = it->get();
2935 // Only examine the object if our m_shouldPaint flag is set.
2936 if (r->shouldPaint()) {
2937 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2938 LayoutUnit floatRight = floatLeft + r->renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002939 left = std::min(left, floatLeft);
2940 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002941 }
2942 }
2943 }
2944}
2945
2946void RenderBlockFlow::fitBorderToLinesIfNeeded()
2947{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002948 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002949 return;
2950
2951 // Walk any normal flow lines to snugly fit.
2952 LayoutUnit left = LayoutUnit::max();
2953 LayoutUnit right = LayoutUnit::min();
2954 LayoutUnit oldWidth = contentWidth();
2955 adjustForBorderFit(0, left, right);
2956
2957 // Clamp to our existing edges. We can never grow. We only shrink.
2958 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2959 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002960 left = std::min(rightEdge, std::max(leftEdge, left));
2961 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002962
2963 LayoutUnit newContentWidth = right - left;
2964 if (newContentWidth == oldWidth)
2965 return;
2966
2967 setOverrideLogicalContentWidth(newContentWidth);
2968 layoutBlock(false);
2969 clearOverrideLogicalContentWidth();
2970}
2971
2972void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2973{
2974 if (logicalTop >= logicalBottom)
2975 return;
2976
antti@apple.combe9d3e12014-05-11 09:42:47 +00002977 // Floats currently affect the choice whether to use simple line layout path.
2978 if (m_simpleLineLayout) {
2979 invalidateLineLayoutPath();
2980 return;
2981 }
2982
weinig@apple.com611b9292013-10-20 22:57:54 +00002983 RootInlineBox* lowestDirtyLine = lastRootBox();
2984 RootInlineBox* afterLowest = lowestDirtyLine;
2985 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2986 afterLowest = lowestDirtyLine;
2987 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2988 }
2989
2990 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2991 afterLowest->markDirty();
2992 afterLowest = afterLowest->prevRootBox();
2993 }
2994}
2995
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002996Optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00002997{
2998 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002999 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003000
3001 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003002 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003003
antti@apple.com940f5872013-10-24 20:31:11 +00003004 if (!hasLines())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003005 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003006
darin@apple.come1be6ca2014-04-28 04:19:10 +00003007 if (auto simpleLineLayout = this->simpleLineLayout())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003008 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003009
akling@apple.comee3c8df2013-11-06 08:09:44 +00003010 ASSERT(firstRootBox());
3011 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003012}
3013
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003014Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003015{
3016 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003017 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003018
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003019 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3020 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3021 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003022 if (!childrenInline()) {
3023 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3024 if (!inlineBlockBaseline)
3025 return inlineBlockBaseline;
3026 lastBaseline = inlineBlockBaseline.value();
3027 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003028 if (!hasLines()) {
3029 if (!hasLineIfEmpty())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003030 return Optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003031 const auto& fontMetrics = firstLineStyle().fontMetrics();
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003032 return Optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003033 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003034 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003035 }
3036
3037 if (auto simpleLineLayout = this->simpleLineLayout())
3038 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3039 else {
3040 bool isFirstLine = lastRootBox() == firstRootBox();
3041 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3042 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3043 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003044 }
3045 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3046 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3047 // enough with the spec to not cause tons of breakages).
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003048 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003049}
3050
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003051void RenderBlockFlow::setSelectionState(SelectionState state)
3052{
3053 if (state != SelectionNone)
3054 ensureLineBoxes();
3055 RenderBoxModelObject::setSelectionState(state);
3056}
3057
weinig@apple.com12840dc2013-10-22 23:59:08 +00003058GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003059 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3060{
antti@apple.comfea51992013-10-28 13:39:23 +00003061 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003062
weinig@apple.com611b9292013-10-20 22:57:54 +00003063 GapRects result;
3064
3065 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3066
antti@apple.com0e632aa2013-10-22 21:03:38 +00003067 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003068 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003069 // 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 +00003070 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3071 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3072 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3073 }
3074 return result;
3075 }
3076
3077 RootInlineBox* lastSelectedLine = 0;
3078 RootInlineBox* curr;
3079 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3080
3081 // Now paint the gaps for the lines.
3082 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3083 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3084 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3085
3086 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003087 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003088 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3089
3090 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3091 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003092 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003093 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3094 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3095 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3096
3097 lastSelectedLine = curr;
3098 }
3099
3100 if (containsStart && !lastSelectedLine)
3101 // VisibleSelection must start just after our last line.
3102 lastSelectedLine = lastRootBox();
3103
3104 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003105 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003106 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3107 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3108 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3109 }
3110 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003111}
3112
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003113void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3114{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003115 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003116 return;
3117
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003118 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3119 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003120 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003121 flowFragment->initializeStyle();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003122 setRenderNamedFlowFragment(flowFragment);
3123 addChild(renderNamedFlowFragment());
3124 }
3125}
3126
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003127bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3128{
3129 // A block without floats or that expands to enclose them won't need a relayout
3130 // after a region range change. There is no overflow content needing relayout
3131 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003132 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003133 return false;
3134
3135 return true;
3136}
3137
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003138bool RenderBlockFlow::canHaveChildren() const
3139{
3140 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3141}
3142
3143bool RenderBlockFlow::canHaveGeneratedChildren() const
3144{
3145 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3146}
3147
3148bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3149{
3150 if (!isRenderNamedFlowFragmentContainer())
3151 return false;
3152
3153 return hasRelativeLogicalHeight() && !isRenderView();
3154}
3155
3156void RenderBlockFlow::updateLogicalHeight()
3157{
3158 RenderBlock::updateLogicalHeight();
3159
abucur@adobe.comfad53712014-05-06 17:30:40 +00003160 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003161 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003162 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3163 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003164}
3165
3166void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3167{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003168 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003169 if (rareData.m_renderNamedFlowFragment)
3170 rareData.m_renderNamedFlowFragment->destroy();
3171 rareData.m_renderNamedFlowFragment = flowFragment;
3172}
3173
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003174void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3175{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003176 if (flowThread || hasRareBlockFlowData()) {
3177 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3178 rareData.m_multiColumnFlowThread = flowThread;
3179 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003180}
3181
akling@apple.com525dae62014-01-03 20:22:09 +00003182static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003183{
akling@apple.com38f0a652014-02-06 21:24:17 +00003184 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003185}
3186
3187RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3188{
3189 ASSERT(i >= 0);
3190
akling@apple.com827be9c2013-10-29 02:58:43 +00003191 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003192 return nullptr;
3193
3194 if (childrenInline()) {
3195 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3196 if (!i--)
3197 return box;
3198 }
akling@apple.com525dae62014-01-03 20:22:09 +00003199 return nullptr;
3200 }
3201
3202 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3203 if (!shouldCheckLines(blockFlow))
3204 continue;
3205 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3206 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003207 }
3208
3209 return nullptr;
3210}
3211
3212int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3213{
akling@apple.com827be9c2013-10-29 02:58:43 +00003214 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003215 return 0;
3216
3217 int count = 0;
3218
3219 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003220 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003221 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003222 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003223 }
weinig@apple.com17140912013-10-19 19:55:40 +00003224 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3225 count++;
3226 if (box == stopRootInlineBox) {
3227 if (found)
3228 *found = true;
3229 break;
3230 }
3231 }
akling@apple.com525dae62014-01-03 20:22:09 +00003232 return count;
3233 }
3234
3235 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3236 if (!shouldCheckLines(blockFlow))
3237 continue;
3238 bool recursiveFound = false;
3239 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3240 if (recursiveFound) {
3241 if (found)
3242 *found = true;
3243 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003244 }
3245 }
3246
3247 return count;
3248}
3249
3250static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3251{
akling@apple.com827be9c2013-10-29 02:58:43 +00003252 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003253 return -1;
3254
3255 if (block.childrenInline()) {
3256 for (auto box = block.firstRootBox(); box; box = box->nextRootBox()) {
3257 if (++count == lineCount)
3258 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3259 }
3260 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003261 RenderBox* normalFlowChildWithoutLines = nullptr;
weinig@apple.com17140912013-10-19 19:55:40 +00003262 for (auto obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003263 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3264 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003265 if (result != -1)
3266 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003267 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003268 normalFlowChildWithoutLines = obj;
3269 }
3270 if (normalFlowChildWithoutLines && !lineCount)
3271 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3272 }
3273
3274 return -1;
3275}
3276
3277int RenderBlockFlow::heightForLineCount(int lineCount)
3278{
3279 int count = 0;
3280 return getHeightForLineCount(*this, lineCount, true, count);
3281}
3282
3283void RenderBlockFlow::clearTruncation()
3284{
akling@apple.com827be9c2013-10-29 02:58:43 +00003285 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003286 return;
3287
3288 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003289 ensureLineBoxes();
3290
weinig@apple.com17140912013-10-19 19:55:40 +00003291 setHasMarkupTruncation(false);
3292 for (auto box = firstRootBox(); box; box = box->nextRootBox())
3293 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003294 return;
3295 }
3296
3297 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3298 if (shouldCheckLines(blockFlow))
3299 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003300 }
3301}
3302
weinig@apple.com3f23b382013-10-19 20:26:58 +00003303bool RenderBlockFlow::containsNonZeroBidiLevel() const
3304{
3305 for (auto root = firstRootBox(); root; root = root->nextRootBox()) {
3306 for (auto box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
3307 if (box->bidiLevel())
3308 return true;
3309 }
3310 }
3311 return false;
3312}
3313
weinig@apple.com611b9292013-10-20 22:57:54 +00003314Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3315{
3316 if (!box)
3317 return Position();
3318
3319 if (!box->renderer().nonPseudoNode())
3320 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3321
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003322 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003323 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3324
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003325 auto& textBox = downcast<InlineTextBox>(*box);
3326 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003327}
3328
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003329VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003330{
3331 ASSERT(childrenInline());
3332
antti@apple.com940f5872013-10-24 20:31:11 +00003333 ensureLineBoxes();
3334
weinig@apple.com611b9292013-10-20 22:57:54 +00003335 if (!firstRootBox())
3336 return createVisiblePosition(0, DOWNSTREAM);
3337
akling@apple.com827be9c2013-10-29 02:58:43 +00003338 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3339 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003340
3341 // look for the closest line box in the root box which is at the passed-in y coordinate
3342 InlineBox* closestBox = 0;
3343 RootInlineBox* firstRootBoxWithChildren = 0;
3344 RootInlineBox* lastRootBoxWithChildren = 0;
3345 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003346 if (region && root->containingRegion() != region)
3347 continue;
3348
weinig@apple.com611b9292013-10-20 22:57:54 +00003349 if (!root->firstLeafChild())
3350 continue;
3351 if (!firstRootBoxWithChildren)
3352 firstRootBoxWithChildren = root;
3353
3354 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3355 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3356 break;
3357
3358 lastRootBoxWithChildren = root;
3359
3360 // check if this root line box is located at this y coordinate
3361 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3362 if (linesAreFlipped) {
3363 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3364 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3365 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3366
3367 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3368 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3369 continue;
3370 }
3371 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3372 if (closestBox)
3373 break;
3374 }
3375 }
3376
3377 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3378
3379 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3380 // y coordinate is below last root line box, pretend we hit it
3381 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3382 }
3383
3384 if (closestBox) {
3385 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003386 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003387 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3388 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3389 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3390 if (box->isLineBreak()) {
3391 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3392 box = newBox;
3393 }
3394 // y coordinate is above first root line box, so return the start of the first
3395 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3396 }
3397 }
3398
3399 // pass the box a top position that is inside it
3400 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3401 if (!isHorizontalWritingMode())
3402 point = point.transposedPoint();
3403 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003404 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003405 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003406 }
3407
3408 if (lastRootBoxWithChildren) {
3409 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3410 ASSERT(moveCaretToBoundary);
3411 InlineBox* logicallyLastBox;
3412 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3413 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3414 }
3415
3416 // Can't reach this. We have a root line box, but it has no kids.
3417 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3418 // seems to hit this code path.
3419 return createVisiblePosition(0, DOWNSTREAM);
3420}
3421
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003422VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003423{
3424 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003425 return fragment->positionForPoint(point, region);
3426 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003427}
3428
3429
weinig@apple.com611b9292013-10-20 22:57:54 +00003430void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3431{
antti@apple.com940f5872013-10-24 20:31:11 +00003432 ASSERT(childrenInline());
3433
3434 ensureLineBoxes();
3435
weinig@apple.com611b9292013-10-20 22:57:54 +00003436 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003437 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3438 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003439 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3440 if (!rect.isEmpty())
zalan@apple.com376339c2014-08-28 04:24:31 +00003441 rects.append(snappedIntRect(rect));
weinig@apple.com611b9292013-10-20 22:57:54 +00003442 }
3443}
3444
3445void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3446{
3447 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003448
darin@apple.come1be6ca2014-04-28 04:19:10 +00003449 if (auto simpleLineLayout = this->simpleLineLayout()) {
3450 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003451 return;
3452 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003453 m_lineBoxes.paint(this, paintInfo, paintOffset);
3454}
3455
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003456bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003457{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003458 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003459 return false;
3460
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003461 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003462 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3463
3464 bool needsRelayout;
3465 bool neededRelayout = false;
3466 bool firstPass = true;
3467 do {
3468 // Column heights may change here because of balancing. We may have to do multiple layout
3469 // passes, depending on how the contents is fitted to the changed column heights. In most
3470 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3471 // passes than that, though, but the number of retries should not exceed the number of
3472 // columns, unless we have a bug.
3473 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003474 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3475 if (multicolSet->recalculateColumnHeight(firstPass))
3476 needsRelayout = true;
3477 if (needsRelayout) {
3478 // Once a column set gets a new column height, that column set and all successive column
3479 // sets need to be laid out over again, since their logical top will be affected by
3480 // this, and therefore their column heights may change as well, at least if the multicol
3481 // height is constrained.
3482 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003483 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003484 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003485 if (needsRelayout) {
3486 // Layout again. Column balancing resulted in a new height.
3487 neededRelayout = true;
3488 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3489 setChildNeedsLayout(MarkOnlyThis);
3490 if (firstPass)
3491 statePusher.pop();
3492 layoutBlock(false);
3493 }
3494 firstPass = false;
3495 } while (needsRelayout);
3496
3497 multiColumnFlowThread()->setInBalancingPass(false);
3498
3499 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003500}
3501
antti@apple.com940f5872013-10-24 20:31:11 +00003502bool RenderBlockFlow::hasLines() const
3503{
3504 ASSERT(childrenInline());
3505
darin@apple.come1be6ca2014-04-28 04:19:10 +00003506 if (auto simpleLineLayout = this->simpleLineLayout())
3507 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003508
3509 return lineBoxes().firstLineBox();
3510}
3511
antti@apple.com9e891c82014-05-22 06:12:34 +00003512void RenderBlockFlow::invalidateLineLayoutPath()
3513{
akling@apple.coma12fee22015-02-01 02:58:13 +00003514 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003515 case UndeterminedPath:
3516 case ForceLineBoxesPath:
3517 ASSERT(!m_simpleLineLayout);
3518 return;
3519 case LineBoxesPath:
3520 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003521 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003522 return;
3523 case SimpleLinesPath:
3524 // The simple line layout may have become invalid.
3525 m_simpleLineLayout = nullptr;
3526 setNeedsLayout();
akling@apple.coma12fee22015-02-01 02:58:13 +00003527 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003528 return;
3529 }
3530 ASSERT_NOT_REACHED();
3531}
3532
zalan@apple.come37da962014-12-11 03:29:29 +00003533void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003534{
zalan@apple.come37da962014-12-11 03:29:29 +00003535 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3536 if (needsLayout) {
3537 deleteLineBoxesBeforeSimpleLineLayout();
3538 m_simpleLineLayout = SimpleLineLayout::create(*this);
3539 }
antti@apple.com940f5872013-10-24 20:31:11 +00003540 ASSERT(!m_lineBoxes.firstLineBox());
3541
antti@apple.comfea51992013-10-28 13:39:23 +00003542 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003543 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003544 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003545 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003546 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3547}
3548
3549void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3550{
akling@apple.coma12fee22015-02-01 02:58:13 +00003551 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003552 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003553 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3554 if (is<RenderText>(renderer))
3555 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3556 else if (is<RenderLineBreak>(renderer))
3557 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3558 else
3559 ASSERT_NOT_REACHED();
3560 }
antti@apple.com940f5872013-10-24 20:31:11 +00003561}
3562
3563void RenderBlockFlow::ensureLineBoxes()
3564{
akling@apple.coma12fee22015-02-01 02:58:13 +00003565 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003566 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003567 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003568 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003569
3570#if !ASSERT_DISABLED
3571 LayoutUnit oldHeight = logicalHeight();
3572#endif
3573 bool didNeedLayout = needsLayout();
3574
3575 bool relayoutChildren = false;
3576 LayoutUnit repaintLogicalTop;
3577 LayoutUnit repaintLogicalBottom;
3578 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3579
3580 updateLogicalHeight();
3581 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3582
3583 if (!didNeedLayout)
3584 clearNeedsLayout();
3585}
3586
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003587#if ENABLE(TREE_DEBUGGING)
zalan@apple.comfac337f2014-08-29 17:55:34 +00003588void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003589{
weinig@apple.com611b9292013-10-20 22:57:54 +00003590 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003591 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003592
3593 if (auto simpleLineLayout = this->simpleLineLayout())
3594 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003595}
3596#endif
3597
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003598RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3599{
3600 if (hasRareBlockFlowData())
3601 return *m_rareBlockFlowData;
3602 materializeRareBlockFlowData();
3603 return *m_rareBlockFlowData;
3604}
3605
3606void RenderBlockFlow::materializeRareBlockFlowData()
3607{
3608 ASSERT(!hasRareBlockFlowData());
3609 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3610}
3611
aestes@apple.com6751d842014-01-12 02:51:25 +00003612#if ENABLE(IOS_TEXT_AUTOSIZING)
3613inline static bool isVisibleRenderText(RenderObject* renderer)
3614{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003615 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003616 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003617 RenderText& renderText = downcast<RenderText>(*renderer);
3618 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003619}
3620
3621inline static bool resizeTextPermitted(RenderObject* render)
3622{
3623 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3624 auto renderer = render->parent();
3625 while (renderer) {
3626 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003627 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003628 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003629 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003630 }
3631 renderer = renderer->parent();
3632 }
3633 return true;
3634}
3635
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003636int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003637{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003638 if (style().visibility() != VISIBLE)
3639 return 0;
3640 if (childrenInline())
3641 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003642 // Only descend into list items.
3643 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003644 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3645 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003646 return count;
3647}
3648
3649static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3650{
3651 if (!render->isRenderBlock())
3652 return true;
3653 if (render->isListItem())
3654 return render->style().height().type() != Fixed;
3655 return false;
3656}
3657
3658// For now, we auto size single lines of text the same as multiple lines.
3659// We've been experimenting with low values for single lines of text.
3660static inline float oneLineTextMultiplier(float specifiedSize)
3661{
3662 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3663}
3664
3665static inline float textMultiplier(float specifiedSize)
3666{
3667 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3668}
3669
3670void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3671{
3672 // Don't do any work if the block is smaller than the visible area.
3673 if (visibleWidth >= width())
3674 return;
3675
3676 unsigned lineCount;
3677 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003678 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003679 if (!count)
3680 lineCount = NO_LINE;
3681 else if (count == 1)
3682 lineCount = ONE_LINE;
3683 else
3684 lineCount = MULTI_LINE;
3685 } else
3686 lineCount = m_lineCountForTextAutosizing;
3687
3688 ASSERT(lineCount != NOT_SET);
3689 if (lineCount == NO_LINE)
3690 return;
3691
3692 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3693 float scale = visibleWidth / actualWidth;
3694 float minFontSize = roundf(size / scale);
3695
3696 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3697 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003698 RenderText& text = downcast<RenderText>(*descendent);
3699 RenderStyle& oldStyle = text.style();
aestes@apple.com6751d842014-01-12 02:51:25 +00003700 FontDescription fontDescription = oldStyle.fontDescription();
3701 float specifiedSize = fontDescription.specifiedSize();
3702 float scaledSize = roundf(specifiedSize * scale);
3703 if (scaledSize > 0 && scaledSize < minFontSize) {
3704 // 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.
3705 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3706 if (m_lineCountForTextAutosizing == NOT_SET)
3707 m_lineCountForTextAutosizing = lineCount;
3708 if (m_widthForTextAutosizing == -1)
3709 m_widthForTextAutosizing = actualWidth;
3710
3711 float candidateNewSize = 0;
3712 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3713 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003714 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3715 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003716 }
3717 }
3718 }
3719}
3720#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3721
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003722RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3723{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003724 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3725 if (!flowThread)
3726 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003727
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003728 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003729
3730 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003731 flowThread->setChildNeedsLayout(MarkOnlyThis);
3732
3733 if (flowThread->needsLayout()) {
3734 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3735 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3736
3737 flowThread->invalidateRegions();
3738 flowThread->setNeedsHeightsRecalculation(true);
3739 flowThread->layout();
3740 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003741 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3742 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3743 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3744 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3745 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3746 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3747 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3748 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003749 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003750 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003751 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003752
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003753 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003754}
3755
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003756void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3757{
3758 if (multiColumnFlowThread())
3759 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003760 if (beforeChild) {
3761 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3762 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3763 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003764 RenderBlock::addChild(newChild, beforeChild);
3765}
3766
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003767void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003768{
3769 if (!documentBeingDestroyed()) {
3770 RenderFlowThread* flowThread = multiColumnFlowThread();
3771 if (flowThread && flowThread != &oldChild)
3772 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3773 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003774 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003775}
3776
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003777void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003778{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003779 // If we don't use columns or flow threads, then bail.
3780 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003781 return;
3782
3783 // 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 +00003784 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3785 LogicalExtentComputedValues computedValues;
3786 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3787 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003788 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003789 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003790 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3791 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003792 } else if (is<RenderFlowThread>(*this)) {
3793 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003794
3795 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3796 // is known. The page logical height thing in LayoutState is meaningless for flow
3797 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3798 // thread), but as long as it is used universally as a means to determine whether page
3799 // height is known or not, we need this. Page height is unknown when column balancing is
3800 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3801 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3802 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3803 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003804 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003805
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003806 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003807 }
3808}
3809
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003810bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3811{
3812 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3813 // in the RenderView instead.
3814 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isRoot() || isBody());
3815
3816 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3817}
3818
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003819void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3820{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003821 bool destroyColumns = !requiresColumns(count);
3822 if (destroyColumns) {
3823 if (multiColumnFlowThread())
3824 destroyMultiColumnFlowThread();
3825 } else {
3826 if (!multiColumnFlowThread())
3827 createMultiColumnFlowThread();
3828 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003829 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3830 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003831 }
3832}
3833
cdumez@apple.com78141732014-11-04 23:00:48 +00003834void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003835{
hyatt@apple.com86919862014-01-27 16:27:45 +00003836 if (!multiColumnFlowThread())
3837 return;
3838
3839 bool needsLayout = false;
3840 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003841 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003842 if (oldProgressionIsInline != newProgressionIsInline) {
3843 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3844 needsLayout = true;
3845 }
3846
3847 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003848 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003849 if (oldProgressionIsReversed != newProgressionIsReversed) {
3850 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3851 needsLayout = true;
3852 }
3853
3854 if (needsLayout)
3855 setNeedsLayoutAndPrefWidthsRecalc();
3856}
3857
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003858LayoutUnit RenderBlockFlow::computedColumnWidth() const
3859{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003860 if (multiColumnFlowThread())
3861 return multiColumnFlowThread()->computedColumnWidth();
3862 return contentLogicalWidth();
3863}
3864
3865unsigned RenderBlockFlow::computedColumnCount() const
3866{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003867 if (multiColumnFlowThread())
3868 return multiColumnFlowThread()->computedColumnCount();
3869
3870 return 1;
3871}
3872
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003873bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3874{
3875 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3876 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3877 return hasTopOverflow;
3878
3879 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3880 hasTopOverflow = !hasTopOverflow;
3881
3882 return hasTopOverflow;
3883}
3884
3885bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3886{
3887 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3888 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3889 return hasLeftOverflow;
3890
3891 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3892 hasLeftOverflow = !hasLeftOverflow;
3893
3894 return hasLeftOverflow;
3895}
3896
zalan@apple.comac6956c2014-09-05 14:18:06 +00003897struct InlineMinMaxIterator {
3898/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3899 inline min/max width calculations. Note the following about the way it walks:
3900 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3901 (2) We do not drill into the children of floats or replaced elements, since you can't break
3902 in the middle of such an element.
3903 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3904 distinct borders/margin/padding that contribute to the min/max width.
3905*/
3906 const RenderBlockFlow& parent;
3907 RenderObject* current;
3908 bool endOfInline;
3909 bool initial;
3910
3911 InlineMinMaxIterator(const RenderBlockFlow& p)
3912 : parent(p)
3913 , current(nullptr)
3914 , endOfInline(false)
3915 , initial(true)
3916 { }
3917
3918 RenderObject* next();
3919};
3920
3921RenderObject* InlineMinMaxIterator::next()
3922{
3923 RenderObject* result = nullptr;
3924 bool oldEndOfInline = endOfInline;
3925 endOfInline = false;
3926 do {
3927 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3928 result = current->firstChildSlow();
3929 else if (initial) {
3930 result = parent.firstChild();
3931 initial = false;
3932 }
3933
3934 if (!result) {
3935 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3936 if (!oldEndOfInline && current && current->isRenderInline()) {
3937 result = current;
3938 endOfInline = true;
3939 break;
3940 }
3941
3942 while (current && current != &parent) {
3943 result = current->nextSibling();
3944 if (result)
3945 break;
3946 current = current->parent();
3947 if (current && current != &parent && current->isRenderInline()) {
3948 result = current;
3949 endOfInline = true;
3950 break;
3951 }
3952 }
3953 }
3954
3955 if (!result)
3956 break;
3957
3958 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3959 break;
3960
3961 current = result;
3962 result = nullptr;
3963 } while (current || current == &parent);
3964 // Update our position.
3965 current = result;
3966 return result;
3967}
3968
3969static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3970{
3971 if (cssUnit.type() != Auto)
3972 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
3973 return 0;
3974}
3975
3976static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
3977{
3978 const RenderStyle& childStyle = child.style();
3979 if (endOfInline) {
3980 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
3981 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
3982 child.borderEnd();
3983 }
3984 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
3985 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
3986 child.borderStart();
3987}
3988
3989static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
3990{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003991 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00003992 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003993 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00003994 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00003995 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003996 float spaceWidth = font.width(RenderBlock::constructTextRun(&renderText, font, &space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00003997 inlineMax -= spaceWidth + font.wordSpacing();
3998 if (inlineMin > inlineMax)
3999 inlineMin = inlineMax;
4000 }
4001}
4002
4003static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4004{
4005 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4006}
4007
4008void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4009{
4010 float inlineMax = 0;
4011 float inlineMin = 0;
4012
4013 const RenderStyle& styleToUse = style();
4014 RenderBlock* containingBlock = this->containingBlock();
4015 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4016
4017 // If we are at the start of a line, we want to ignore all white-space.
4018 // Also strip spaces if we previously had text that ended in a trailing space.
4019 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004020 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004021
4022 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4023 // very specific cirucumstances (in order to match common WinIE renderings).
4024 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4025 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4026
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004027 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004028
4029 InlineMinMaxIterator childIterator(*this);
4030
4031 // Only gets added to the max preffered width once.
4032 bool addedTextIndent = false;
4033 // Signals the text indent was more negative than the min preferred width
4034 bool hasRemainingNegativeTextIndent = false;
4035
4036 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4037 RenderObject* prevFloat = 0;
4038 bool isPrevChildInlineFlow = false;
4039 bool shouldBreakLineAfterText = false;
4040 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004041 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004042 child->style().autoWrap();
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004043 bool isAnonymousInlineBlock = child->isAnonymousInlineBlock();
4044
zalan@apple.comac6956c2014-09-05 14:18:06 +00004045 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004046 // Step One: determine whether or not we need to terminate our current line.
4047 // Each discrete chunk can become the new min-width, if it is the widest chunk
4048 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004049
4050 // Children fall into three categories:
4051 // (1) An inline flow object. These objects always have a min/max of 0,
4052 // and are included in the iteration solely so that their margins can
4053 // be added in.
4054 //
4055 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4056 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004057 // we need to break the current line, and then add in our own margins and min/max
4058 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004059 //
4060 // (3) A text object. Text runs can have breakable characters at the start,
4061 // the middle or the end. They may also lose whitespace off the front if
4062 // we're already ignoring whitespace. In order to compute accurate min-width
4063 // information, we need three pieces of information.
4064 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4065 // starts with whitespace.
4066 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4067 // ends with whitespace.
4068 // (c) the min/max width of the string (trimmed for whitespace).
4069 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004070 // If the text string starts with whitespace, then we need to terminate our current line
4071 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004072 //
4073 // If the text string has a breakable character in the middle, but didn't start
4074 // with whitespace, then we add the width of the first non-breakable run and
4075 // then end the current line. We then need to use the intermediate min/max width
4076 // values (if any of them are larger than our current min/max). We then look at
4077 // the width of the last non-breakable run and use that to start a new line
4078 // (unless we end in whitespace).
4079 const RenderStyle& childStyle = child->style();
4080 float childMin = 0;
4081 float childMax = 0;
4082
4083 if (!child->isText()) {
4084 if (child->isLineBreakOpportunity()) {
4085 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4086 inlineMin = 0;
4087 continue;
4088 }
4089 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004090 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004091 // Add in padding/border/margin from the appropriate side of
4092 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004093 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004094 childMin += bpm;
4095 childMax += bpm;
4096
4097 inlineMin += childMin;
4098 inlineMax += childMax;
4099
4100 child->setPreferredLogicalWidthsDirty(false);
4101 } else {
4102 // Inline replaced elts add in their margins to their min/max values.
4103 LayoutUnit margins = 0;
4104 Length startMargin = childStyle.marginStart();
4105 Length endMargin = childStyle.marginEnd();
4106 if (startMargin.isFixed())
4107 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4108 if (endMargin.isFixed())
4109 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4110 childMin += margins.ceilToFloat();
4111 childMax += margins.ceilToFloat();
4112 }
4113 }
4114
cdumez@apple.comf8022152014-10-15 00:29:51 +00004115 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004116 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004117 // Terminate the current line as far as minwidth is concerned.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004118 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4119 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4120
4121 bool clearPreviousFloat;
4122 if (child->isFloating()) {
4123 clearPreviousFloat = (prevFloat
4124 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4125 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4126 prevFloat = child;
4127 } else
4128 clearPreviousFloat = false;
4129
4130 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004131 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) || isAnonymousInlineBlock) {
4132 if (child->isAnonymousInlineBlock() && styleToUse.collapseWhiteSpace())
4133 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004134 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4135 inlineMin = 0;
4136 }
4137
4138 // If we're supposed to clear the previous float, then terminate maxwidth as well.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004139 if (clearPreviousFloat || isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004140 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4141 inlineMax = 0;
4142 }
4143
4144 // Add in text-indent. This is added in only once.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004145 if (!addedTextIndent && !child->isFloating() && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004146 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4147 childMin += ceiledIndent;
4148 childMax += ceiledIndent;
4149
4150 if (childMin < 0)
4151 textIndent = LayoutUnit::fromFloatCeil(childMin);
4152 else
4153 addedTextIndent = true;
4154 }
4155
4156 // Add our width to the max.
4157 inlineMax += std::max<float>(0, childMax);
4158
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004159 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004160 if (child->isFloating())
4161 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4162 else
4163 inlineMin += childMin;
4164 } else {
4165 // Now check our line.
4166 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4167
4168 // Now start a new line.
4169 inlineMin = 0;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004170
4171 if (child->isAnonymousInlineBlock()) {
4172 // Terminate max width as well.
4173 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4174 inlineMax = 0;
4175 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004176 }
4177
4178 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4179 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4180 inlineMin = 0;
4181 }
4182
4183 // We are no longer stripping whitespace at the start of a line.
4184 if (!child->isFloating()) {
4185 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004186 trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004187 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004188 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004189 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004190 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004191
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004192 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4193 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004194
4195 // Determine if we have a breakable character. Pass in
4196 // whether or not we should ignore any spaces at the front
4197 // of the string. If those are going to be stripped out,
4198 // then they shouldn't be considered in the breakable char
4199 // check.
4200 bool hasBreakableChar, hasBreak;
4201 float beginMin, endMin;
4202 bool beginWS, endWS;
4203 float beginMax, endMax;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004204 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004205 hasBreakableChar, hasBreak, beginMax, endMax,
4206 childMin, childMax, stripFrontSpaces);
4207
4208 // This text object will not be rendered, but it may still provide a breaking opportunity.
4209 if (!hasBreak && !childMax) {
4210 if (autoWrap && (beginWS || endWS)) {
4211 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4212 inlineMin = 0;
4213 }
4214 continue;
4215 }
4216
4217 if (stripFrontSpaces)
4218 trailingSpaceChild = child;
4219 else
4220 trailingSpaceChild = 0;
4221
4222 // Add in text-indent. This is added in only once.
4223 float ti = 0;
4224 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4225 ti = textIndent.ceilToFloat();
4226 childMin += ti;
4227 beginMin += ti;
4228
4229 // It the text indent negative and larger than the child minimum, we re-use the remainder
4230 // in future minimum calculations, but using the negative value again on the maximum
4231 // will lead to under-counting the max pref width.
4232 if (!addedTextIndent) {
4233 childMax += ti;
4234 beginMax += ti;
4235 addedTextIndent = true;
4236 }
4237
4238 if (childMin < 0) {
4239 textIndent = childMin;
4240 hasRemainingNegativeTextIndent = true;
4241 }
4242 }
4243
4244 // If we have no breakable characters at all,
4245 // then this is the easy case. We add ourselves to the current
4246 // min and max and continue.
4247 if (!hasBreakableChar)
4248 inlineMin += childMin;
4249 else {
4250 // We have a breakable character. Now we need to know if
4251 // we start and end with whitespace.
4252 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004253 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004254 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4255 } else {
4256 inlineMin += beginMin;
4257 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4258 childMin -= ti;
4259 }
4260
4261 inlineMin = childMin;
4262
4263 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004264 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004265 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4266 inlineMin = 0;
4267 shouldBreakLineAfterText = false;
4268 } else {
4269 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4270 inlineMin = endMin;
4271 shouldBreakLineAfterText = true;
4272 }
4273 }
4274
4275 if (hasBreak) {
4276 inlineMax += beginMax;
4277 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4278 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4279 inlineMax = endMax;
4280 addedTextIndent = true;
4281 } else
4282 inlineMax += std::max<float>(0, childMax);
4283 }
4284
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004285 // Ignore spaces after a list marker and also after an anonymous inline block.
4286 if (child->isListMarker() || isAnonymousInlineBlock)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004287 stripFrontSpaces = true;
4288 } else {
4289 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4290 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4291 inlineMin = inlineMax = 0;
4292 stripFrontSpaces = true;
4293 trailingSpaceChild = 0;
4294 addedTextIndent = true;
4295 }
4296
4297 if (!child->isText() && child->isRenderInline())
4298 isPrevChildInlineFlow = true;
4299 else
4300 isPrevChildInlineFlow = false;
4301
4302 oldAutoWrap = autoWrap;
4303 }
4304
4305 if (styleToUse.collapseWhiteSpace())
4306 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4307
4308 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4309 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4310}
4311
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004312}
4313// namespace WebCore