blob: ad2e477acf8a3861410a102460c6a2bc7ca1ce52 [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"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000040#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000041#include "RenderMarquee.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000042#include "RenderMultiColumnFlowThread.h"
43#include "RenderMultiColumnSet.h"
mihnea@adobe.combe79cf12013-10-17 09:02:19 +000044#include "RenderNamedFlowFragment.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000045#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000046#include "RenderText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000047#include "RenderView.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000048#include "Settings.h"
antti@apple.com940f5872013-10-24 20:31:11 +000049#include "SimpleLineLayoutFunctions.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000050#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000051#include "VisiblePosition.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000052#include <wtf/NeverDestroyed.h>
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000053
hyatt@apple.com5388e672013-09-06 20:54:47 +000054namespace WebCore {
55
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000056bool RenderBlock::s_canPropagateFloatIntoSibling = false;
57
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000058struct SameSizeAsMarginInfo {
59 uint32_t bitfields : 16;
60 LayoutUnit margins[2];
61};
62
63COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000064COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000065
66// Our MarginInfo state used when laying out block children.
weinig@apple.com12840dc2013-10-22 23:59:08 +000067RenderBlockFlow::MarginInfo::MarginInfo(RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000068 : m_atBeforeSideOfBlock(true)
69 , m_atAfterSideOfBlock(false)
70 , m_hasMarginBeforeQuirk(false)
71 , m_hasMarginAfterQuirk(false)
72 , m_determinedMarginBeforeQuirk(false)
73 , m_discardMargin(false)
74{
akling@apple.com827be9c2013-10-29 02:58:43 +000075 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000076 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000077 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000078
akling@apple.com827be9c2013-10-29 02:58:43 +000079 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000080
81 // If any height other than auto is specified in CSS, then we don't collapse our bottom
82 // margins with our children's margins. To do otherwise would be to risk odd visual
83 // effects when the children overflow out of the parent block and yet still collapse
84 // with it. We also don't collapse if we have any bottom border/padding.
85 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000086 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000087
weinig@apple.com12840dc2013-10-22 23:59:08 +000088 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000089
weinig@apple.com12840dc2013-10-22 23:59:08 +000090 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000091
weinig@apple.com12840dc2013-10-22 23:59:08 +000092 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
93 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000094}
95
akling@apple.com689f7612014-12-14 08:21:05 +000096RenderBlockFlow::RenderBlockFlow(Element& element, Ref<RenderStyle>&& style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +000097 : RenderBlock(element, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +000098#if ENABLE(IOS_TEXT_AUTOSIZING)
99 , m_widthForTextAutosizing(-1)
100 , m_lineCountForTextAutosizing(NOT_SET)
101#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000102{
weinig@apple.com611b9292013-10-20 22:57:54 +0000103 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000104}
105
akling@apple.com689f7612014-12-14 08:21:05 +0000106RenderBlockFlow::RenderBlockFlow(Document& document, Ref<RenderStyle>&& style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +0000107 : RenderBlock(document, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000108#if ENABLE(IOS_TEXT_AUTOSIZING)
109 , m_widthForTextAutosizing(-1)
110 , m_lineCountForTextAutosizing(NOT_SET)
111#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000112{
weinig@apple.com611b9292013-10-20 22:57:54 +0000113 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000114}
115
116RenderBlockFlow::~RenderBlockFlow()
117{
118}
119
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000120void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000121{
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000122 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
123 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000124 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 +0000125 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000126 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000127 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 +0000128 setMultiColumnFlowThread(flowThread);
129}
130
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000131void RenderBlockFlow::destroyMultiColumnFlowThread()
132{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000133 multiColumnFlowThread()->evacuateAndDestroy();
134 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000135}
136
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000137void RenderBlockFlow::insertedIntoTree()
138{
139 RenderBlock::insertedIntoTree();
140 createRenderNamedFlowFragmentIfNeeded();
141}
142
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000143void RenderBlockFlow::willBeDestroyed()
144{
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000145 if (renderNamedFlowFragment())
146 setRenderNamedFlowFragment(0);
weinig@apple.com611b9292013-10-20 22:57:54 +0000147
weinig@apple.com611b9292013-10-20 22:57:54 +0000148 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
149 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
150 destroyLeftoverChildren();
151
weinig@apple.com611b9292013-10-20 22:57:54 +0000152 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000153 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000154 // We can't wait for RenderBox::destroy to clear the selection,
155 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000156 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000157 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000158
159 // If we are an anonymous block, then our line boxes might have children
160 // that will outlast this block. In the non-anonymous block case those
161 // children will be destroyed by the time we return from this function.
162 if (isAnonymousBlock()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000163 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000164 while (auto childBox = box->firstChild())
165 childBox->removeFromParent();
166 }
167 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000168 } else if (parent())
169 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000170 }
171
akling@apple.com31dd4f42013-10-30 22:27:59 +0000172 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000173
dbates@webkit.org34f59002014-05-20 20:34:35 +0000174 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000175
176 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
177 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000178}
179
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000180RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
181{
182 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
183 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
184 // to avoid floats.
185 parentHasFloats = false;
186 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
187 if (is<RenderBlockFlow>(*sibling)) {
188 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
189 if (!siblingBlock.avoidsFloats())
190 return &siblingBlock;
191 }
192 if (sibling->isFloating())
193 parentHasFloats = true;
194 }
195 return nullptr;
196}
197
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000198void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000199{
200 if (m_floatingObjects)
201 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
202
203 HashSet<RenderBox*> oldIntrudingFloatSet;
204 if (!childrenInline() && m_floatingObjects) {
205 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000206 auto end = floatingObjectSet.end();
207 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
208 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000209 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000210 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000211 }
212 }
213
214 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
215 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000216 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000217 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000218 if (!oldIntrudingFloatSet.isEmpty())
219 markAllDescendantsWithFloatsForLayout();
220 return;
221 }
222
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000223 RendererToFloatInfoMap floatMap;
224
225 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000226 if (childrenInline())
227 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
228 else
229 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000230 }
231
232 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
233 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
234 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000235 bool isBlockInsideInline = isAnonymousInlineBlock();
236 if (!is<RenderBlockFlow>(parent()) && !isBlockInsideInline)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000237 return;
238
robert@webkit.org97037ef2013-11-20 19:26:10 +0000239 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
240 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000241 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(isBlockInsideInline ? *containingBlock() : *parent());
242 bool parentHasFloats = isBlockInsideInline ? parentBlock.containsFloats() : false;
243 RenderBlockFlow* previousBlock = nullptr;
244 if (!isBlockInsideInline)
245 previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000246 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000247 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000248 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000249
250 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000251 if (previousBlock)
252 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000253 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000254 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000255 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000256 }
257
258 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000259 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000260 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000261
262 if (childrenInline()) {
263 LayoutUnit changeLogicalTop = LayoutUnit::max();
264 LayoutUnit changeLogicalBottom = LayoutUnit::min();
265 if (m_floatingObjects) {
266 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000267 auto end = floatingObjectSet.end();
268 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000269 FloatingObject* floatingObject = it->get();
270 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject->renderer());
271 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000272 if (oldFloatingObject) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000273 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
274 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000275 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000276 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000277 } else {
278 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000279 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
280 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000281 }
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000282 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
283 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000284 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000285 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
286 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000287 }
288 }
289
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000290 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
291 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
292 oldFloatingObject->originatingLine()->markDirty();
293 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000294 } else {
295 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000296 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000297 }
298 }
299 }
300
darin@apple.com7cad7042013-09-24 05:53:55 +0000301 auto end = floatMap.end();
302 for (auto it = floatMap.begin(); it != end; ++it) {
303 FloatingObject* floatingObject = it->value.get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000304 if (!floatingObject->isDescendant()) {
305 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000306 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000307 }
308 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000309
310 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
311 } else if (!oldIntrudingFloatSet.isEmpty()) {
312 // If there are previously intruding floats that no longer intrude, then children with floats
313 // should also get layout because they might need their floating object lists cleared.
314 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
315 markAllDescendantsWithFloatsForLayout();
316 else {
317 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000318 auto end = floatingObjectSet.end();
319 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
320 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000321 if (!oldIntrudingFloatSet.isEmpty())
322 markAllDescendantsWithFloatsForLayout();
323 }
324 }
325}
326
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000327void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
328{
329 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
330 // The min/max intrinsic widths calculated really tell how much space elements need when
331 // laid out inside the columns. In order to eventually end up with the desired column width,
332 // we need to convert them to values pertaining to the multicol container.
333 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
334 LayoutUnit columnWidth;
335 LayoutUnit colGap = columnGap();
336 LayoutUnit gapExtra = (columnCount - 1) * colGap;
337 if (style().hasAutoColumnWidth())
338 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
339 else {
340 columnWidth = style().columnWidth();
341 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
342 }
343 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
344 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
345 // performing a layout pass, but this is not an appropriate time or place for layout. The
346 // good news is that if height is unconstrained and there are no explicit breaks, the
347 // resolved column-count really should be 1.
348 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
349 }
350}
351
352void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
353{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000354 if (childrenInline())
355 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
356 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000357 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
358
359 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
360
361 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
362
363 if (!style().autoWrap() && childrenInline()) {
364 // A horizontal marquee with inline children has no minimum width.
365 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
366 minLogicalWidth = 0;
367 }
368
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000369 if (is<RenderTableCell>(*this)) {
370 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000371 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
372 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
373 }
374
375 int scrollbarWidth = instrinsicScrollbarLogicalWidth();
376 maxLogicalWidth += scrollbarWidth;
377 minLogicalWidth += scrollbarWidth;
378}
379
380bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
381{
382 bool changed = recomputeLogicalWidth();
383
384 LayoutUnit oldColumnWidth = computedColumnWidth();
385 computeColumnCountAndWidth();
386
387 return changed || oldColumnWidth != computedColumnWidth();
388}
389
390LayoutUnit RenderBlockFlow::columnGap() const
391{
392 if (style().hasNormalColumnGap())
393 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
394 return style().columnGap();
395}
396
397void RenderBlockFlow::computeColumnCountAndWidth()
398{
399 // Calculate our column width and column count.
400 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
401 unsigned desiredColumnCount = 1;
402 LayoutUnit desiredColumnWidth = contentLogicalWidth();
403
404 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
405 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
406 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
407 return;
408 }
409
410 LayoutUnit availWidth = desiredColumnWidth;
411 LayoutUnit colGap = columnGap();
412 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
413 int colCount = std::max<int>(1, style().columnCount());
414
415 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
416 desiredColumnCount = colCount;
417 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
418 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
419 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
420 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
421 } else {
422 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
423 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
424 }
425 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
426}
427
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000428void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
429{
430 ASSERT(needsLayout());
431
432 if (!relayoutChildren && simplifiedLayout())
433 return;
434
435 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
436
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000437 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000438 relayoutChildren = true;
439
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000440 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000441
442 LayoutUnit previousHeight = logicalHeight();
443 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
444 // for consistency with other render classes?
445 setLogicalHeight(0);
446
447 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000448 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000449
akling@apple.com827be9c2013-10-29 02:58:43 +0000450 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000451 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000452
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000453 preparePaginationBeforeBlockLayout(relayoutChildren);
abucur@adobe.com0e81bc72013-10-22 14:50:37 +0000454 if (!relayoutChildren)
455 relayoutChildren = namedFlowFragmentNeedsUpdate();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000456
457 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
458 // our current maximal positive and negative margins. These values are used when we
459 // are collapsed with adjacent blocks, so for example, if you have block A and B
460 // collapsing together, then you'd take the maximal positive margin from both A and B
461 // and subtract it from the maximal negative margin from both A and B to get the
462 // true collapsed margin. This algorithm is recursive, so when we finish layout()
463 // our block knows its current maximal positive/negative values.
464 //
465 // Start out by setting our margin values to our current margins. Table cells have
466 // no margins, so we don't fill in the values for table cells.
467 bool isCell = isTableCell();
468 if (!isCell) {
469 initMaxMarginValues();
470
akling@apple.com827be9c2013-10-29 02:58:43 +0000471 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
472 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000473 setPaginationStrut(0);
474 }
475
476 LayoutUnit repaintLogicalTop = 0;
477 LayoutUnit repaintLogicalBottom = 0;
478 LayoutUnit maxFloatLogicalBottom = 0;
479 if (!firstChild() && !isAnonymousBlock())
480 setChildrenInline(true);
481 if (childrenInline())
482 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
483 else
484 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
485
486 // Expand our intrinsic height to encompass floats.
487 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000488 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000489 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
490
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000491 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000492 ASSERT(!shouldBreakAtLineToAvoidWidow());
493 return;
494 }
495
496 // Calculate our new height.
497 LayoutUnit oldHeight = logicalHeight();
498 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
499
500 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
501 // This ensures the size information is correctly computed for the last auto-height region receiving content.
cdumez@apple.com3abcc792014-10-20 03:42:03 +0000502 if (is<RenderFlowThread>(*this))
503 downcast<RenderFlowThread>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000504
505 updateLogicalHeight();
506 LayoutUnit newHeight = logicalHeight();
507 if (oldHeight != newHeight) {
508 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
509 // 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 +0000510 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
511 if (blockFlow.isFloatingOrOutOfFlowPositioned())
512 continue;
513 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
514 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000515 }
516 }
517 }
518
519 bool heightChanged = (previousHeight != newHeight);
520 if (heightChanged)
521 relayoutChildren = true;
522
523 layoutPositionedObjects(relayoutChildren || isRoot());
524
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000525 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
526 computeOverflow(oldClientAfterEdge);
527
528 statePusher.pop();
529
530 fitBorderToLinesIfNeeded();
531
532 if (view().layoutState()->m_pageLogicalHeight)
533 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
534
535 updateLayerTransform();
536
537 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
538 // we overflow or not.
539 updateScrollInfoAfterLayout();
540
541 // FIXME: This repaint logic should be moved into a separate helper function!
542 // Repaint with our new bounds if they are different from our old bounds.
543 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000544 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000545 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
546 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
547 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
548 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
549 if (hasOverflowClip()) {
550 // 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.
551 // 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.
552 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000553 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
554 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000555 }
556
557 LayoutRect repaintRect;
558 if (isHorizontalWritingMode())
559 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
560 else
561 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
562
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000563 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
564
565 if (hasOverflowClip()) {
566 // Adjust repaint rect for scroll offset
567 repaintRect.move(-scrolledContentOffset());
568
569 // Don't allow this rect to spill out of our overflow box.
570 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
571 }
572
573 // Make sure the rect is still non-empty after intersecting for overflow above
574 if (!repaintRect.isEmpty()) {
575 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
576 if (hasReflection())
577 repaintRectangle(reflectedRect(repaintRect));
578 }
579 }
580
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000581 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000582}
583
584void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
585{
586 dirtyForLayoutFromPercentageHeightDescendants();
587
588 LayoutUnit beforeEdge = borderAndPaddingBefore();
589 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
590
591 setLogicalHeight(beforeEdge);
592
593 // Lay out our hypothetical grid line as though it occurs at the top of the block.
594 if (view().layoutState()->lineGrid() == this)
595 layoutLineGridBox();
596
597 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000598 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000599
600 // Fieldsets need to find their legend and position it inside the border of the object.
601 // The legend then gets skipped during normal layout. The same is true for ruby text.
602 // It doesn't get included in the normal layout process but is instead skipped.
603 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
604
605 LayoutUnit previousFloatLogicalBottom = 0;
606 maxFloatLogicalBottom = 0;
607
608 RenderBox* next = firstChildBox();
609
610 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000611 RenderBox& child = *next;
612 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000613
weinig@apple.com12840dc2013-10-22 23:59:08 +0000614 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000615 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
616
617 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
618
weinig@apple.com12840dc2013-10-22 23:59:08 +0000619 if (child.isOutOfFlowPositioned()) {
620 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000621 adjustPositionedBlock(child, marginInfo);
622 continue;
623 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000624 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000625 insertFloatingObject(child);
626 adjustFloatingBlock(marginInfo);
627 continue;
628 }
629
630 // Lay out the child.
631 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
632 }
633
634 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
635 // determining the correct collapsed bottom margin information.
636 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
637}
638
antti@apple.com940f5872013-10-24 20:31:11 +0000639void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
640{
akling@apple.coma12fee22015-02-01 02:58:13 +0000641 if (lineLayoutPath() == UndeterminedPath)
642 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000643
akling@apple.coma12fee22015-02-01 02:58:13 +0000644 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000645 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000646 return;
647 }
648
antti@apple.comfea51992013-10-28 13:39:23 +0000649 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000650 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
651}
652
weinig@apple.com12840dc2013-10-22 23:59:08 +0000653void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000654{
655 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
656 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
657
658 // The child is a normal flow object. Compute the margins we will use for collapsing now.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000659 child.computeAndSetBlockDirectionMargins(this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000660
661 // Try to guess our correct logical top position. In most cases this guess will
662 // be correct. Only if we're wrong (when we compute the real logical top position)
663 // will we have to potentially relayout.
664 LayoutUnit estimateWithoutPagination;
665 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
666
667 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000668 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000669 LayoutUnit oldLogicalTop = logicalTopForChild(child);
670
671#if !ASSERT_DISABLED
672 LayoutSize oldLayoutDelta = view().layoutDelta();
673#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000674 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000675 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
676 estimateRegionRangeForBoxChild(child);
677
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000678 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000679 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000680 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000681 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000682 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
683 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
684 // very large elements. If it does the comparison with oldLogicalTop might yield a
685 // false negative as adding and removing margins, borders etc from a saturated number
686 // might yield incorrect results. If this is the case always mark for layout.
687 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000688 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000689 // If an element might be affected by the presence of floats, then always mark it for
690 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000691 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000692 if (fb > logicalTopEstimate)
693 markDescendantsWithFloats = true;
694 }
695
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000696 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000697 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000698 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000699 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000700 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000701 }
702
hyatt@apple.comccad3742015-02-04 21:39:00 +0000703 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000704
weinig@apple.com12840dc2013-10-22 23:59:08 +0000705 bool childHadLayout = child.everHadLayout();
706 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000707 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000708 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000709
710 // Cache if we are at the top of the block right now.
711 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
712
713 // Now determine the correct ypos based off examination of collapsing margin
714 // values.
715 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
716
717 // Now check for clear.
718 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
719
720 bool paginated = view().layoutState()->isPaginated();
721 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000722 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000723
724 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
725
726 // Now we have a final top position. See if it really does end up being different from our estimate.
727 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
728 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000729 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
730 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000731 // The child's width depends on the line width. When the child shifts to clear an item, its width can
732 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000733 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000734 }
735
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000736 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000737 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000738 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000739 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000740 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000741 }
742
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000743 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000744 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000745
746 // In case our guess was wrong, relayout the child.
747 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000748
749 // We are no longer at the top of the block if we encounter a non-empty child.
750 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000751 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000752 marginInfo.setAtBeforeSideOfBlock(false);
753
754 // Now place the child in the correct left position
755 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
756
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000757 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000758 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000759 if (mustSeparateMarginAfterForChild(child)) {
760 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
761 marginInfo.clearMargin();
762 }
763 // If the child has overhanging floats that intrude into following siblings (or possibly out
764 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000765 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000766 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000767
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000768 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000769 if (childOffset.width() || childOffset.height()) {
770 view().addLayoutDelta(childOffset);
771
772 // If the child moved, we have to repaint it as well as any floating/positioned
773 // descendants. An exception is if we need a layout. In this case, we know we're going to
774 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000775 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
776 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000777 }
778
weinig@apple.com12840dc2013-10-22 23:59:08 +0000779 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
780 child.repaint();
781 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000782 }
783
784 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000785 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
786 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000787 // Check for an after page/column break.
788 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
789 if (newHeight != height())
790 setLogicalHeight(newHeight);
791 }
792
793 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
794}
795
weinig@apple.com12840dc2013-10-22 23:59:08 +0000796void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000797{
798 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000799 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000800
801 LayoutUnit logicalTop = logicalHeight();
802 updateStaticInlinePositionForChild(child, logicalTop);
803
804 if (!marginInfo.canCollapseWithMarginBefore()) {
805 // Positioned blocks don't collapse margins, so add the margin provided by
806 // the container now. The child's own margin is added later when calculating its logical top.
807 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
808 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
809 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
810 }
811
weinig@apple.com12840dc2013-10-22 23:59:08 +0000812 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000813 if (childLayer->staticBlockPosition() != logicalTop) {
814 childLayer->setStaticBlockPosition(logicalTop);
815 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000816 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000817 }
818}
819
robert@webkit.org97037ef2013-11-20 19:26:10 +0000820LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
821{
822 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000823 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000824 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
825 return marginValuesForChild(*this).positiveMarginBefore();
826 return LayoutUnit();
827}
828
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000829void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
830{
831 LayoutUnit startPosition = borderStart() + paddingStart();
832 if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
833 startPosition -= verticalScrollbarWidth();
834 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
835
836 // Add in our start margin.
837 LayoutUnit childMarginStart = marginStartForChild(child);
838 LayoutUnit newPosition = startPosition + childMarginStart;
839
840 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
841 // to shift over as necessary to dodge any floats that might get in the way.
842 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
843 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
844
845 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
846}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000847
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000848void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
849{
850 // The float should be positioned taking into account the bottom margin
851 // of the previous flow. We add that margin into the height, get the
852 // float positioned properly, and then subtract the margin out of the
853 // height again. In the case of self-collapsing blocks, we always just
854 // use the top margins, since the self-collapsing block collapsed its
855 // own bottom margin into its top margin.
856 //
857 // Note also that the previous flow may collapse its margin into the top of
858 // our block. If this is the case, then we do not add the margin in to our
859 // height when computing the position of the float. This condition can be tested
860 // for by simply calling canCollapseWithMarginBefore. See
861 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
862 // an example of this scenario.
863 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
864 setLogicalHeight(logicalHeight() + marginOffset);
865 positionNewFloats();
866 setLogicalHeight(logicalHeight() - marginOffset);
867}
868
weinig@apple.com12840dc2013-10-22 23:59:08 +0000869void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop)
870{
akling@apple.com827be9c2013-10-29 02:58:43 +0000871 if (child.style().isOriginalDisplayInlineType())
weinig@apple.com12840dc2013-10-22 23:59:08 +0000872 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
873 else
874 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
875}
876
877void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
878{
879 if (flowThreadContainingBlock()) {
880 // Shift the inline position to exclude the region offset.
881 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
882 }
883 child.layer()->setStaticInlinePosition(inlinePosition);
884}
885
886RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000887{
888 LayoutUnit childBeforePositive = 0;
889 LayoutUnit childBeforeNegative = 0;
890 LayoutUnit childAfterPositive = 0;
891 LayoutUnit childAfterNegative = 0;
892
893 LayoutUnit beforeMargin = 0;
894 LayoutUnit afterMargin = 0;
895
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000896 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000897
898 // If the child has the same directionality as we do, then we can just return its
899 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000900 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000901 if (childRenderBlock) {
902 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
903 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
904 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
905 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
906 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000907 beforeMargin = child.marginBefore();
908 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000909 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000910 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000911 // The child has a different directionality. If the child is parallel, then it's just
912 // flipped relative to us. We can use the margins for the opposite edges.
913 if (childRenderBlock) {
914 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
915 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
916 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
917 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
918 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000919 beforeMargin = child.marginAfter();
920 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000921 }
922 } else {
923 // The child is perpendicular to us, which means its margins don't collapse but are on the
924 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
925 beforeMargin = marginBeforeForChild(child);
926 afterMargin = marginAfterForChild(child);
927 }
928
929 // Resolve uncollapsing margins into their positive/negative buckets.
930 if (beforeMargin) {
931 if (beforeMargin > 0)
932 childBeforePositive = beforeMargin;
933 else
934 childBeforeNegative = -beforeMargin;
935 }
936 if (afterMargin) {
937 if (afterMargin > 0)
938 childAfterPositive = afterMargin;
939 else
940 childAfterNegative = -afterMargin;
941 }
942
943 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
944}
945
weinig@apple.com12840dc2013-10-22 23:59:08 +0000946LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000947{
948 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
949 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +0000950 bool childIsSelfCollapsing = child.isSelfCollapsingBlock();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000951
952 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
953 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
954
955 // Get the four margin values for the child and cache them.
956 const MarginValues childMargins = marginValuesForChild(child);
957
958 // Get our max pos and neg top margins.
959 LayoutUnit posTop = childMargins.positiveMarginBefore();
960 LayoutUnit negTop = childMargins.negativeMarginBefore();
961
962 // For self-collapsing blocks, collapse our bottom margins into our
963 // top to get new posTop and negTop values.
964 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000965 posTop = std::max(posTop, childMargins.positiveMarginAfter());
966 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000967 }
968
969 // See if the top margin is quirky. We only care if this child has
970 // margins that will collapse with us.
971 bool topQuirk = hasMarginBeforeQuirk(child);
972
973 if (marginInfo.canCollapseWithMarginBefore()) {
974 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
975 // This child is collapsing with the top of the
976 // block. If it has larger margin values, then we need to update
977 // our own maximal values.
978 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +0000979 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000980
981 // The minute any of the margins involved isn't a quirk, don't
982 // collapse it away, even if the margin is smaller (www.webreference.com
983 // has an example of this, a <dt> with 0.8em author-specified inside
984 // a <dl> inside a <td>.
985 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
986 setHasMarginBeforeQuirk(false);
987 marginInfo.setDeterminedMarginBeforeQuirk(true);
988 }
989
990 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
991 // We have no top margin and our top child has a quirky margin.
992 // We will pick up this quirky margin and pass it through.
993 // This deals with the <td><div><p> case.
994 // Don't do this for a block that split two inlines though. You do
995 // still apply margins in this case.
996 setHasMarginBeforeQuirk(true);
997 } else
998 // The before margin of the container will also discard all the margins it is collapsing with.
999 setMustDiscardMarginBefore();
1000 }
1001
1002 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1003 if (childDiscardMarginBefore) {
1004 marginInfo.setDiscardMargin(true);
1005 marginInfo.clearMargin();
1006 }
1007
1008 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1009 marginInfo.setHasMarginBeforeQuirk(topQuirk);
1010
1011 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1012 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001013
1014 LayoutUnit clearanceForSelfCollapsingBlock;
1015 RenderObject* prev = child.previousSibling();
1016 // 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
1017 // 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
1018 // 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 +00001019 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prev) && downcast<RenderBlockFlow>(*prev).isSelfCollapsingBlock()) {
1020 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prev).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001021 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1022 }
1023
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001024 if (childIsSelfCollapsing) {
1025 // 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.
1026 // Also, the child's top position equals the logical height of the container.
1027 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1028 // This child has no height. We need to compute our
1029 // position before we collapse the child's margins together,
1030 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001031 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1032 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001033 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1034
1035 // Now collapse the child's margins together, which means examining our
1036 // bottom margin values as well.
1037 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1038 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1039
1040 if (!marginInfo.canCollapseWithMarginBefore())
1041 // We need to make sure that the position of the self-collapsing block
1042 // is correct, since it could have overflowing content
1043 // that needs to be positioned correctly (e.g., a block that
1044 // had a specified height of 0 but that actually had subcontent).
1045 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1046 }
1047 } else {
1048 if (mustSeparateMarginBeforeForChild(child)) {
1049 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1050 // If we are at the before side of the block and we collapse, ignore the computed margin
1051 // and just add the child margin to the container height. This will correctly position
1052 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001053 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001054 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
1055 logicalTop = logicalHeight();
1056 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1057 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1058 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1059 // We're collapsing with a previous sibling's margins and not
1060 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001061 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001062 logicalTop = logicalHeight();
1063 }
1064
1065 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1066
1067 if (!marginInfo.discardMargin()) {
1068 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1069 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1070 } else
1071 marginInfo.clearMargin();
1072
1073 if (marginInfo.margin())
1074 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
1075 }
1076
1077 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1078 // collapsed into the page edge.
1079 LayoutState* layoutState = view().layoutState();
1080 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1081 && hasNextPage(beforeCollapseLogicalTop)) {
1082 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001083 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001084 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1085 }
1086
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001087 if (is<RenderBlockFlow>(prev) && !prev->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001088 // 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
1089 // any floats from the parent will now overhang.
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001090 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prev);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001091 LayoutUnit oldLogicalHeight = logicalHeight();
1092 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001093 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001094 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001095 setLogicalHeight(oldLogicalHeight);
1096
1097 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1098 // 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
1099 // floats in the parent that overhang |child|'s new logical top.
1100 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
1101 if (logicalTopIntrudesIntoFloat && containsFloats() && !child.avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1102 child.setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001103 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001104
1105 return logicalTop;
1106}
1107
weinig@apple.com12840dc2013-10-22 23:59:08 +00001108LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001109{
1110 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1111 if (!heightIncrease)
1112 return yPos;
1113
weinig@apple.com12840dc2013-10-22 23:59:08 +00001114 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001115 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1116
1117 // For self-collapsing blocks that clear, they can still collapse their
1118 // margins with following siblings. Reset the current margins to represent
1119 // the self-collapsing block's margins only.
1120 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001121 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001122 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001123 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1124 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001125 } else
1126 marginInfo.clearMargin();
1127 marginInfo.setDiscardMargin(childDiscardMargin);
1128
1129 // CSS2.1 states:
1130 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1131 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1132 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1133 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1134 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001135 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001136 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1137 wouldCollapseMarginsWithParent = false;
1138 }
1139 if (wouldCollapseMarginsWithParent)
1140 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1141
robert@webkit.org97037ef2013-11-20 19:26:10 +00001142 // 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
1143 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1144 // 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
1145 // margins can collapse at the correct vertical position.
1146 // 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
1147 // (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],
1148 // i.e., clearance = [height of float] - margin-top".
1149 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001150 } else
1151 // Increase our height by the amount we had to clear.
1152 setLogicalHeight(logicalHeight() + heightIncrease);
1153
1154 if (marginInfo.canCollapseWithMarginBefore()) {
1155 // We can no longer collapse with the top of the block since a clear
1156 // occurred. The empty blocks collapse into the cleared block.
1157 // FIXME: This isn't quite correct. Need clarification for what to do
1158 // if the height the cleared block is offset by is smaller than the
1159 // margins involved.
1160 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1161 marginInfo.setAtBeforeSideOfBlock(false);
1162
1163 // 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 +00001164 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001165 }
1166
robert@webkit.org97037ef2013-11-20 19:26:10 +00001167 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001168}
1169
weinig@apple.com12840dc2013-10-22 23:59:08 +00001170void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001171{
1172 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1173 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1174 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001175 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001176 return;
1177
1178 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1179 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001180 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001181 positiveMarginBefore = 0;
1182 negativeMarginBefore = 0;
1183 discardMarginBefore = true;
1184 return;
1185 }
1186
1187 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001188 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1189 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001190
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001191 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001192 return;
1193
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001194 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001195 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001196 return;
1197
weinig@apple.com12840dc2013-10-22 23:59:08 +00001198 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001199 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1200 return;
1201
weinig@apple.com12840dc2013-10-22 23:59:08 +00001202 RenderBox* grandchildBox = childBlock.firstChildBox();
1203 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001204 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1205 break;
1206 }
1207
1208 // 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 +00001209 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001210 return;
1211
1212 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1213 if (grandchildBox->needsLayout()) {
1214 grandchildBox->computeAndSetBlockDirectionMargins(this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001215 if (is<RenderBlock>(*grandchildBox)) {
1216 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1217 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1218 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001219 }
1220 }
1221
1222 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001223 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001224}
1225
weinig@apple.com12840dc2013-10-22 23:59:08 +00001226LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001227{
1228 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1229 // relayout if there are intruding floats.
1230 LayoutUnit logicalTopEstimate = logicalHeight();
1231 if (!marginInfo.canCollapseWithMarginBefore()) {
1232 LayoutUnit positiveMarginBefore = 0;
1233 LayoutUnit negativeMarginBefore = 0;
1234 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001235 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001236 // Try to do a basic estimation of how the collapse is going to go.
1237 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1238 } else {
1239 // Use the cached collapsed margin values from a previous layout. Most of the time they
1240 // will be right.
1241 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001242 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1243 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001244 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1245 }
1246
1247 // Collapse the result with our current margins.
1248 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001249 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001250 }
1251
1252 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1253 // page.
1254 LayoutState* layoutState = view().layoutState();
1255 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1256 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001257 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001258
1259 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1260
1261 estimateWithoutPagination = logicalTopEstimate;
1262
1263 if (layoutState->isPaginated()) {
1264 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1265 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1266
1267 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1268 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1269
cdumez@apple.come9437792014-10-08 23:33:43 +00001270 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1271 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001272 }
1273
1274 return logicalTopEstimate;
1275}
1276
1277void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1278{
1279 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1280 // 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.
1281 // Don't update the max margin values because we won't need them anyway.
1282 if (marginInfo.discardMargin()) {
1283 setMustDiscardMarginAfter();
1284 return;
1285 }
1286
1287 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1288 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001289 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001290
1291 if (!marginInfo.hasMarginAfterQuirk())
1292 setHasMarginAfterQuirk(false);
1293
1294 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1295 // We have no bottom margin and our last child has a quirky margin.
1296 // We will pick up this quirky margin and pass it through.
1297 // This deals with the <td><div><p> case.
1298 setHasMarginAfterQuirk(true);
1299 }
1300}
1301
1302void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1303{
1304 marginInfo.setAtAfterSideOfBlock(true);
1305
robert@webkit.org97037ef2013-11-20 19:26:10 +00001306 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1307 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1308 // to perform now is at the child's margin-top - so adjust our height to that position.
1309 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001310 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1311 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001312
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001313 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001314 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1315 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1316 setLogicalHeight(logicalHeight() + marginInfo.margin());
1317
1318 // Now add in our bottom border/padding.
1319 setLogicalHeight(logicalHeight() + afterSide);
1320
1321 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1322 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001323 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001324
1325 // Update our bottom collapsed margin info.
1326 setCollapsedBottomMargin(marginInfo);
1327}
1328
1329void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1330{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001331 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001332 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001333 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001334 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001335 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001336
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001337 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1338 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001339}
1340
1341void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1342{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001343 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001344 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001345 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001346 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001347 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001348
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001349 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1350 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001351}
1352
1353void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1354{
akling@apple.com827be9c2013-10-29 02:58:43 +00001355 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001356 ASSERT(value);
1357 return;
1358 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001359
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001360 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001361 if (!value)
1362 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001363 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001364 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001365
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001366 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001367}
1368
1369void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1370{
akling@apple.com827be9c2013-10-29 02:58:43 +00001371 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001372 ASSERT(value);
1373 return;
1374 }
1375
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001376 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001377 if (!value)
1378 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001379 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001380 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001381
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001382 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001383}
1384
1385bool RenderBlockFlow::mustDiscardMarginBefore() const
1386{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001387 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001388}
1389
1390bool RenderBlockFlow::mustDiscardMarginAfter() const
1391{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001392 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001393}
1394
weinig@apple.com12840dc2013-10-22 23:59:08 +00001395bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001396{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001397 ASSERT(!child.selfNeedsLayout());
1398 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001399 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001400 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001401 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001402
1403 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1404 // In case the boxes are perpendicular we assume the property is not specified.
1405 return false;
1406}
1407
weinig@apple.com12840dc2013-10-22 23:59:08 +00001408bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001409{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001410 ASSERT(!child.selfNeedsLayout());
1411 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001412 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001413 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001414 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001415
1416 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1417 return false;
1418}
1419
weinig@apple.com12840dc2013-10-22 23:59:08 +00001420bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001421{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001422 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001423 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001424 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001425 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001426 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001427 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001428
1429 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1430 return false;
1431}
1432
weinig@apple.com12840dc2013-10-22 23:59:08 +00001433bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001434{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001435 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001436 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001437 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001438 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001439 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001440 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001441
1442 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1443 return false;
1444}
1445
weinig@apple.com12840dc2013-10-22 23:59:08 +00001446static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001447{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001448 RenderBlock* curr = child.containingBlock();
1449 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001450 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001451 return true;
1452 if (curr->isFloatingOrOutOfFlowPositioned())
1453 return false;
1454 curr = curr->containingBlock();
1455 }
1456 return true;
1457}
1458
weinig@apple.com12840dc2013-10-22 23:59:08 +00001459LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001460{
1461 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001462 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001463 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001464 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001465 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 +00001466 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001467 bool checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
1468 || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001469 || (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001470 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001471 if (checkColumnBreaks) {
1472 if (isInsideMulticolFlowThread)
1473 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001474 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001475 if (checkRegionBreaks) {
1476 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001477 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001478 return logicalOffset + offsetBreakAdjustment;
1479 }
1480 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1481 }
1482 return logicalOffset;
1483}
1484
weinig@apple.com12840dc2013-10-22 23:59:08 +00001485LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001486{
1487 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001488 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001489 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001490 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001491 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 +00001492 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001493 bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
1494 || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001495 || (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001496 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1497 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1498
1499 // So our margin doesn't participate in the next collapsing steps.
1500 marginInfo.clearMargin();
1501
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001502 if (checkColumnBreaks) {
1503 if (isInsideMulticolFlowThread)
1504 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001505 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001506 if (checkRegionBreaks) {
1507 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001508 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001509 return logicalOffset + marginOffset + offsetBreakAdjustment;
1510 }
1511 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1512 }
1513 return logicalOffset;
1514}
1515
weinig@apple.com12840dc2013-10-22 23:59:08 +00001516LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001517{
cdumez@apple.come9437792014-10-08 23:33:43 +00001518 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001519
1520 if (estimateWithoutPagination != logicalTopAfterClear) {
1521 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1522 // position.
1523 setLogicalHeight(logicalTopAfterClear);
1524 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1525
weinig@apple.com12840dc2013-10-22 23:59:08 +00001526 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001527 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1528 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001529 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001530 }
1531
1532 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001533 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001534 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001535 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001536 }
1537
1538 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001539 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001540 }
1541
1542 LayoutUnit oldTop = logicalTopAfterClear;
1543
1544 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1545 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1546
1547 if (pageLogicalHeightForOffset(result)) {
1548 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001549 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001550 if (spaceShortage > 0) {
1551 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1552 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1553 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1554 // This should be improved, though, because here we just pretend that the child is
1555 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1556 // where there's no child content, border or padding. In other words, we risk stretching more
1557 // than necessary.
1558 setPageBreak(result, spaceShortage);
1559 }
1560 }
1561
1562 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1563 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1564 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1565
1566 LayoutUnit paginationStrut = 0;
1567 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1568 if (unsplittableAdjustmentDelta)
1569 paginationStrut = unsplittableAdjustmentDelta;
1570 else if (childRenderBlock && childRenderBlock->paginationStrut())
1571 paginationStrut = childRenderBlock->paginationStrut();
1572
1573 if (paginationStrut) {
1574 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1575 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1576 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1577 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1578 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1579 // and pushes to the next page anyway, so not too concerned about it.
1580 setPaginationStrut(result + paginationStrut);
1581 if (childRenderBlock)
1582 childRenderBlock->setPaginationStrut(0);
1583 } else
1584 result += paginationStrut;
1585 }
1586
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001587 // 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 +00001588 setLogicalHeight(logicalHeight() + (result - oldTop));
1589
1590 // Return the final adjusted logical top.
1591 return result;
1592}
1593
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001594static inline LayoutUnit calculateMinimumPageHeight(RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001595{
1596 // We may require a certain minimum number of lines per page in order to satisfy
1597 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001598 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001599 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001600 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001601 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1602 line = line->prevRootBox();
1603
1604 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1605 // adjustLinePositionForPagination() for more details.
1606 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001607 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001608 }
1609 return lineBottom - lineTop;
1610}
1611
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001612static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1613{
1614 bool appleMailPaginationQuirkEnabled = lineBox.renderer().document().settings()->appleMailPaginationQuirkEnabled();
1615 if (appleMailPaginationQuirkEnabled && lineBox.renderer().element() && lineBox.renderer().element()->idForStyleResolution() == AtomicString("messageContentContainer", AtomicString::ConstructFromLiteral))
1616 return true;
1617
1618 return false;
1619}
1620
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001621void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001622{
1623 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1624 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1625 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1626 // of the first column.
1627 //
1628 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1629 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1630 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1631 // for overflow to occur), and then cache visible overflow for each column rect.
1632 //
1633 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1634 // content that paints in a previous column (and content that paints in the following column).
1635 //
1636 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1637 // at least make positive leading work in typical cases.
1638 //
1639 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1640 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1641 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001642 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001643 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001644 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1645 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001646 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001647 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001648 logicalOffset += delta;
1649 lineBox->setPaginationStrut(0);
1650 lineBox->setIsFirstAfterPageBreak(false);
1651 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1652 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1653 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1654 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001655 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001656 // 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.
1657 // 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 +00001658 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001659 }
1660
1661 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1662 // 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
1663 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1664 // 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
1665 // top of the page.
1666 // 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
1667 // this will be a real-world issue. For now we don't try to deal with this problem.
1668 logicalOffset = intMaxForLayoutUnit;
1669 logicalBottom = intMinForLayoutUnit;
1670 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1671 lineHeight = logicalBottom - logicalOffset;
1672 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1673 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1674 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1675 }
1676
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001677 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001678 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001679
1680 int lineIndex = lineCount(lineBox);
1681 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001682 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001683 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001684 setDidBreakAtLineToAvoidWidow();
1685 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001686 // If we have a non-uniform page height, then we have to shift further possibly.
1687 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1688 return;
1689 if (lineHeight > pageLogicalHeight) {
1690 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001691 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001692 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001693 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1694 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001695 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001696 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1697 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001698 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001699 && !isOutOfFlowPositioned() && !isTableCell()) {
1700 auto firstRootBox = this->firstRootBox();
1701 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1702 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001703 if (needsAppleMailPaginationQuirk(*lineBox))
1704 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001705 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1706 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001707 delta += remainingLogicalHeight;
1708 lineBox->setPaginationStrut(remainingLogicalHeight);
1709 lineBox->setIsFirstAfterPageBreak(true);
1710 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001711 } else if (remainingLogicalHeight == pageLogicalHeight) {
1712 // We're at the very top of a page or column.
1713 if (lineBox != firstRootBox())
1714 lineBox->setIsFirstAfterPageBreak(true);
1715 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1716 setPageBreak(logicalOffset, lineHeight);
1717 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001718}
1719
1720void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1721{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001722 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001723 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1724 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001725}
1726
abucur@adobe.comfc497132013-10-04 08:49:21 +00001727void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1728{
1729 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001730 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001731 return;
1732
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001733 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001734}
1735
1736void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1737{
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 = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001742}
1743
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001744void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1745{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001746 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001747 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001748 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001749
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001750 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001751}
1752
1753bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1754{
1755 if (!shouldBreakAtLineToAvoidWidow())
1756 return false;
1757
1758 statePusher.pop();
1759 setEverHadLayout(true);
1760 layoutBlock(false);
1761 return true;
1762}
1763
weinig@apple.com31324fd2013-10-28 19:22:51 +00001764bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1765{
1766 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1767
1768 RenderFlowThread* flowThread = flowThreadContainingBlock();
1769 if (!flowThread)
1770 return true; // Printing and multi-column both make new pages to accommodate content.
1771
1772 // See if we're in the last region.
1773 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001774 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001775 if (!region)
1776 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001777
weinig@apple.com31324fd2013-10-28 19:22:51 +00001778 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001779 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001780 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001781
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001782 RenderRegion* startRegion = nullptr;
1783 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001784 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001785 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001786}
1787
1788LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1789{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001790 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001791 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001792
1793 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001794 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1795 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1796 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1797 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1798 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1799 || !hasNextPage(logicalOffset))
1800 return logicalOffset;
1801 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1802 if (remainingLogicalHeight < childLogicalHeight) {
1803 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1804 return logicalOffset;
1805 return logicalOffset + remainingLogicalHeight;
1806 }
1807 return logicalOffset;
1808}
1809
1810bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1811{
1812 bool checkRegion = false;
1813 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1814 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1815 if (minimumLogicalHeight <= pageLogicalHeight)
1816 return true;
1817 if (!hasNextPage(logicalOffset + adjustment))
1818 return false;
1819 adjustment += pageLogicalHeight;
1820 checkRegion = true;
1821 }
1822 return !checkRegion;
1823}
1824
1825void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1826{
1827 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1828 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1829}
1830
1831void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1832{
1833 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1834 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001835}
1836
1837LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1838{
1839 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1840 if (!pageLogicalHeight)
1841 return logicalOffset;
1842
1843 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1844 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1845 if (pageBoundaryRule == ExcludePageBoundary)
1846 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1847 return logicalOffset + remainingLogicalHeight;
1848}
1849
1850LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1851{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001852 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1853 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1854 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1855 if (!pageLogicalHeight)
1856 return 0;
1857
weinig@apple.com31324fd2013-10-28 19:22:51 +00001858 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1859 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1860
1861 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1862 RenderFlowThread* flowThread = flowThreadContainingBlock();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001863 if (!flowThread)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001864 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001865 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001866}
1867
1868LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1869{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001870 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1871 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1872 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1873 if (!pageLogicalHeight)
1874 return 0;
1875
1876 // Now check for a flow thread.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001877 RenderFlowThread* flowThread = flowThreadContainingBlock();
1878 if (!flowThread)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001879 return pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001880 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1881}
1882
1883LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1884{
1885 offset += offsetFromLogicalTopOfFirstPage();
1886
1887 RenderFlowThread* flowThread = flowThreadContainingBlock();
1888 if (!flowThread) {
1889 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1890 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1891 if (pageBoundaryRule == IncludePageBoundary) {
1892 // If includeBoundaryPoint is true the line exactly on the top edge of a
1893 // column will act as being part of the previous column.
1894 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1895 }
1896 return remainingHeight;
1897 }
1898
1899 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1900}
1901
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001902LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1903{
1904 // This method is required because regions do not fragment monolithic elements but instead
1905 // they let them overflow the region they flow in. This behaviour is different from the
1906 // multicol/printing implementations, which have not yet been updated to correctly handle
1907 // monolithic elements.
1908 // As a result, for the moment, this method will only be used for regions, the multicol and
1909 // printing implementations will stick to the existing behaviour until their fragmentation
1910 // implementation is updated to match the regions implementation.
1911 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1912 return logicalHeightForChild(child);
1913
1914 // For unsplittable elements, this method will just return the height of the element that
1915 // fits into the current region, without the height of the part that overflows the region.
1916 // This is done for all regions, except the last one because in that case, the logical
1917 // height of the flow thread needs to also
1918 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1919 return logicalHeightForChild(child);
1920
1921 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1922 // the entire unsplittable child because any following children will not be moved to the next page
1923 // so they will need to be laid out below the current unsplittable child.
1924 LayoutUnit childLogicalTop = logicalTopForChild(child);
1925 if (!hasNextPage(childLogicalTop))
1926 return logicalHeightForChild(child);
1927
1928 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1929 return std::min(child.logicalHeight(), remainingLogicalHeight);
1930}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001931
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001932void RenderBlockFlow::layoutLineGridBox()
1933{
akling@apple.com827be9c2013-10-29 02:58:43 +00001934 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001935 setLineGridBox(0);
1936 return;
1937 }
1938
1939 setLineGridBox(0);
1940
akling@apple.com1aa97b02013-10-31 21:59:49 +00001941 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001942 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1943 lineGridBox->setConstructed();
1944 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1945 VerticalPositionCache verticalPositionCache;
1946 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1947
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00001948 setLineGridBox(WTF::move(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001949
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001950 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1951 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1952 // to this grid.
1953}
1954
weinig@apple.com12840dc2013-10-22 23:59:08 +00001955bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001956{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001957 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001958}
1959
1960void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1961{
1962 RenderBlock::styleDidChange(diff, oldStyle);
1963
1964 // After our style changed, if we lose our ability to propagate floats into next sibling
1965 // blocks, then we need to find the top most parent containing that overhanging float and
1966 // then mark its descendants with floats for layout and clear all floats from its next
1967 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1968 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1969 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
1970 RenderBlockFlow* parentBlock = this;
1971 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001972
weinig@apple.comc77041e2013-12-14 18:05:45 +00001973 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
1974 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00001975 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00001976 if (ancestor.hasOverhangingFloats()) {
akling@apple.comf3028052013-11-04 08:46:06 +00001977 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
1978 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00001979 if (ancestor.hasOverhangingFloat(renderer)) {
1980 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00001981 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001982 }
1983 }
1984 }
1985 }
1986
1987 parentBlock->markAllDescendantsWithFloatsForLayout();
1988 parentBlock->markSiblingsWithFloatsForLayout();
1989 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00001990
akling@apple.com8f40c5b2013-10-27 22:54:07 +00001991 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00001992 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00001993
antti@apple.com9e891c82014-05-22 06:12:34 +00001994 if (diff >= StyleDifferenceRepaint) {
1995 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
1996 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
1997 invalidateLineLayoutPath();
1998 }
1999
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002000 if (multiColumnFlowThread())
2001 updateStylesForColumnChildren();
2002}
2003
2004void RenderBlockFlow::updateStylesForColumnChildren()
2005{
2006 for (auto child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
2007 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002008}
2009
akling@apple.combdae43242013-10-25 12:00:20 +00002010void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002011{
akling@apple.com827be9c2013-10-29 02:58:43 +00002012 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002013 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2014
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002015 if (oldStyle) {
2016 EPosition oldPosition = oldStyle->position();
2017 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002018
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002019 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2020 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2021 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002022 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002023 }
2024
2025 RenderBlock::styleWillChange(diff, newStyle);
2026}
2027
antti@apple.coma2c7f242013-10-22 22:37:25 +00002028void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002029{
2030 if (containsFloats())
2031 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002032
antti@apple.comfea51992013-10-28 13:39:23 +00002033 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002034 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002035 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002036 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002037 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002038
antti@apple.coma2c7f242013-10-22 22:37:25 +00002039 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002040}
2041
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002042void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002043{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002044 // When a portion of the render tree is being detached, anonymous blocks
2045 // will be combined as their children are deleted. In this process, the
2046 // anonymous block later in the tree is merged into the one preceeding it.
2047 // It can happen that the later block (this) contains floats that the
2048 // previous block (toBlockFlow) did not contain, and thus are not in the
2049 // floating objects list for toBlockFlow. This can result in toBlockFlow
2050 // containing floats that are not in it's floating objects list, but are in
2051 // the floating objects lists of siblings and parents. This can cause
2052 // problems when the float itself is deleted, since the deletion code
2053 // assumes that if a float is not in it's containing block's floating
2054 // objects list, it isn't in any floating objects list. In order to
2055 // preserve this condition (removing it has serious performance
2056 // implications), we need to copy the floating objects from the old block
2057 // (this) to the new block (toBlockFlow). The float's metrics will likely
2058 // all be wrong, but since toBlockFlow is already marked for layout, this
2059 // will get fixed before anything gets displayed.
2060 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2061 if (m_floatingObjects) {
2062 if (!toBlockFlow->m_floatingObjects)
2063 toBlockFlow->createFloatingObjects();
2064
2065 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2066 auto end = fromFloatingObjectSet.end();
2067
2068 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2069 FloatingObject* floatingObject = it->get();
2070
2071 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002072 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002073 continue;
2074
2075 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2076 }
2077 }
2078}
2079
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002080void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002081{
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002082 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2083 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2084 moveFloatsTo(&toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002085}
2086
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002087void RenderBlockFlow::addOverflowFromFloats()
2088{
2089 if (!m_floatingObjects)
2090 return;
2091
2092 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2093 auto end = floatingObjectSet.end();
2094 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2095 FloatingObject* r = it->get();
2096 if (r->isDescendant())
2097 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
2098 }
2099}
2100
2101void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2102{
2103 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2104
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002105 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002106 addOverflowFromFloats();
2107}
2108
2109void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2110{
2111 // Repaint any overhanging floats (if we know we're the one to paint them).
2112 // Otherwise, bail out.
2113 if (!hasOverhangingFloats())
2114 return;
2115
2116 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2117 // in this block. Better yet would be to push extra state for the containers of other floats.
2118 LayoutStateDisabler layoutStateDisabler(&view());
2119 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2120 auto end = floatingObjectSet.end();
2121 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2122 FloatingObject* floatingObject = it->get();
2123 // Only repaint the object if it is overhanging, is not in its own layer, and
2124 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2125 // condition is replaced with being a descendant of us.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002126 if (logicalBottomForFloat(floatingObject) > logicalHeight()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002127 && !floatingObject->renderer().hasSelfPaintingLayer()
2128 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
2129 floatingObject->renderer().repaint();
2130 floatingObject->renderer().repaintOverhangingFloats(false);
2131 }
2132 }
2133}
2134
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002135void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002136{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002137 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002138
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002139 if (!multiColumnFlowThread() || paintInfo.context->paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002140 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002141
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002142 // Iterate over our children and paint the column rules as needed.
2143 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2144 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2145 columnSet.paintColumnRules(paintInfo, childPoint);
2146 }
2147}
2148
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002149void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2150{
2151 if (!m_floatingObjects)
2152 return;
2153
2154 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2155 auto end = floatingObjectSet.end();
2156 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2157 FloatingObject* r = it->get();
2158 // Only paint the object if our m_shouldPaint flag is set.
2159 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
2160 PaintInfo currentPaintInfo(paintInfo);
2161 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2162 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
2163 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2164 r->renderer().paint(currentPaintInfo, childPoint);
2165 if (!preservePhase) {
2166 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2167 r->renderer().paint(currentPaintInfo, childPoint);
2168 currentPaintInfo.phase = PaintPhaseFloat;
2169 r->renderer().paint(currentPaintInfo, childPoint);
2170 currentPaintInfo.phase = PaintPhaseForeground;
2171 r->renderer().paint(currentPaintInfo, childPoint);
2172 currentPaintInfo.phase = PaintPhaseOutline;
2173 r->renderer().paint(currentPaintInfo, childPoint);
2174 }
2175 }
2176 }
2177}
2178
weinig@apple.com12840dc2013-10-22 23:59:08 +00002179void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002180{
2181 if (m_floatingObjects) {
2182 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2183 auto end = floatingObjectSet.end();
2184 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2185 FloatingObject* floatingObject = it->get();
2186 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2187 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
2188 floatingObject->renderer().width(), floatingObject->renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002189 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002190 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
zalan@apple.com376339c2014-08-28 04:24:31 +00002191 paintInfo->context->clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002192 }
2193 }
2194}
2195
2196void RenderBlockFlow::createFloatingObjects()
2197{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002198 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002199}
2200
2201void RenderBlockFlow::removeFloatingObjects()
2202{
2203 if (!m_floatingObjects)
2204 return;
2205
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002206 markSiblingsWithFloatsForLayout();
2207
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002208 m_floatingObjects->clear();
2209}
2210
weinig@apple.com12840dc2013-10-22 23:59:08 +00002211FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002212{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002213 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002214
2215 // Create the list of special objects if we don't aleady have one
2216 if (!m_floatingObjects)
2217 createFloatingObjects();
2218 else {
2219 // Don't insert the floatingObject again if it's already in the list
2220 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002221 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002222 if (it != floatingObjectSet.end())
2223 return it->get();
2224 }
2225
2226 // Create the special floatingObject entry & append it to the list
2227
weinig@apple.com12840dc2013-10-22 23:59:08 +00002228 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002229
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002230 // 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 +00002231 bool isChildRenderBlock = floatBox.isRenderBlock();
2232 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2233 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002234
2235 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002236 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2237 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002238 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002239 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2240 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002241 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002242 floatBox.updateLogicalWidth();
2243 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002244 }
2245
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002246 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002247
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00002248 return m_floatingObjects->add(WTF::move(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002249}
2250
weinig@apple.com12840dc2013-10-22 23:59:08 +00002251void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002252{
2253 if (m_floatingObjects) {
2254 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002255 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002256 if (it != floatingObjectSet.end()) {
2257 FloatingObject* floatingObject = it->get();
2258 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002259 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2260 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002261
2262 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2263 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2264 logicalBottom = LayoutUnit::max();
2265 else {
2266 // Special-case zero- and less-than-zero-height floats: those don't touch
2267 // the line that they're on, but it still needs to be dirtied. This is
2268 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002269 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002270 }
2271 if (floatingObject->originatingLine()) {
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002272 floatingObject->originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002273 if (!selfNeedsLayout()) {
2274 ASSERT(&floatingObject->originatingLine()->renderer() == this);
2275 floatingObject->originatingLine()->markDirty();
2276 }
2277#if !ASSERT_DISABLED
2278 floatingObject->setOriginatingLine(0);
2279#endif
2280 }
2281 markLinesDirtyInBlockRange(0, logicalBottom);
2282 }
2283 m_floatingObjects->remove(floatingObject);
2284 }
2285 }
2286}
2287
2288void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2289{
2290 if (!containsFloats())
2291 return;
2292
2293 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2294 FloatingObject* curr = floatingObjectSet.last().get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002295 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002296 m_floatingObjects->remove(curr);
2297 if (floatingObjectSet.isEmpty())
2298 break;
2299 curr = floatingObjectSet.last().get();
2300 }
2301}
2302
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002303LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2304{
2305 LayoutUnit offset = fixedOffset;
2306 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2307 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2308 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2309}
2310
2311LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2312{
2313 LayoutUnit offset = fixedOffset;
2314 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2315 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2316 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2317}
2318
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002319LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002320{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002321 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002322 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002323 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002324
andersca@apple.com86298632013-11-10 19:32:33 +00002325 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002326
2327 LayoutUnit floatLogicalLeft;
2328
2329 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002330 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2331
2332 if (isInitialLetter) {
2333 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2334 if (letterClearance > 0) {
2335 logicalTopOffset += letterClearance;
2336 setLogicalHeight(logicalHeight() + letterClearance);
2337 }
2338 }
2339
akling@apple.com827be9c2013-10-29 02:58:43 +00002340 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002341 LayoutUnit heightRemainingLeft = 1;
2342 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002343 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2344 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002345 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002346 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002347 if (insideFlowThread) {
2348 // Have to re-evaluate all of our offsets, since they may have changed.
2349 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2350 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002351 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002352 }
2353 }
andersca@apple.com86298632013-11-10 19:32:33 +00002354 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002355 } else {
2356 LayoutUnit heightRemainingLeft = 1;
2357 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002358 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2359 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002360 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002361 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002362 if (insideFlowThread) {
2363 // Have to re-evaluate all of our offsets, since they may have changed.
2364 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2365 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002366 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002367 }
2368 }
2369 // Use the original width of the float here, since the local variable
2370 // |floatLogicalWidth| was capped to the available line width. See
2371 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002372 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002373 }
2374
hyatt@apple.com87515262014-09-04 21:20:12 +00002375 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002376 const RenderStyle& style = firstLineStyle();
2377 const FontMetrics& fontMetrics = style.fontMetrics();
2378 if (fontMetrics.hasCapHeight()) {
2379 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2380 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2381
2382 // Make an adjustment to align with the cap height of a theoretical block line.
2383 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2384 logicalTopOffset += adjustment;
2385
2386 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2387 // positive for raised and negative for sunken).
2388 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2389
2390 // 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.
2391 if (dropHeightDelta < 0) {
2392 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2393 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2394 }
2395
2396 // 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
2397 // empty lines beside the first letter.
2398 if (dropHeightDelta > 0)
2399 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2400 }
2401 }
2402
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002403 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2404}
2405
2406bool RenderBlockFlow::positionNewFloats()
2407{
2408 if (!m_floatingObjects)
2409 return false;
2410
2411 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2412 if (floatingObjectSet.isEmpty())
2413 return false;
2414
2415 // If all floats have already been positioned, then we have no work to do.
2416 if (floatingObjectSet.last()->isPlaced())
2417 return false;
2418
2419 // Move backwards through our floating object list until we find a float that has
2420 // already been positioned. Then we'll be able to move forward, positioning all of
2421 // the new floats that need it.
2422 auto it = floatingObjectSet.end();
2423 --it; // Go to last item.
2424 auto begin = floatingObjectSet.begin();
2425 FloatingObject* lastPlacedFloatingObject = 0;
2426 while (it != begin) {
2427 --it;
2428 if ((*it)->isPlaced()) {
2429 lastPlacedFloatingObject = it->get();
2430 ++it;
2431 break;
2432 }
2433 }
2434
2435 LayoutUnit logicalTop = logicalHeight();
2436
2437 // The float cannot start above the top position of the last positioned float.
2438 if (lastPlacedFloatingObject)
andersca@apple.com86298632013-11-10 19:32:33 +00002439 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002440
2441 auto end = floatingObjectSet.end();
2442 // Now walk through the set of unpositioned floats and place them.
2443 for (; it != end; ++it) {
2444 FloatingObject* floatingObject = it->get();
2445 // The containing block is responsible for positioning floats, so if we have floats in our
2446 // list that come from somewhere else, do not attempt to position them.
2447 if (floatingObject->renderer().containingBlock() != this)
2448 continue;
2449
weinig@apple.com12840dc2013-10-22 23:59:08 +00002450 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002451
akling@apple.com827be9c2013-10-29 02:58:43 +00002452 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002453
weinig@apple.com12840dc2013-10-22 23:59:08 +00002454 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002455
akling@apple.com827be9c2013-10-29 02:58:43 +00002456 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002457 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002458 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002459 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002460
2461 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2462
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002463 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002464
2465 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2466 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2467
2468 estimateRegionRangeForBoxChild(childBox);
2469
hyatt@apple.comccad3742015-02-04 21:39:00 +00002470 childBox.markForPaginationRelayoutIfNeeded();
2471 childBox.layoutIfNeeded();
2472
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002473 LayoutState* layoutState = view().layoutState();
2474 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002475 if (isPaginated) {
2476 // If we are unsplittable and don't fit, then we need to move down.
2477 // We include our margins as part of the unsplittable area.
2478 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2479
2480 // See if we have a pagination strut that is making us move down further.
2481 // Note that an unsplittable child can't also have a pagination strut, so this is
2482 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002483 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002484 if (childBlock && childBlock->paginationStrut()) {
2485 newLogicalTop += childBlock->paginationStrut();
2486 childBlock->setPaginationStrut(0);
2487 }
2488
2489 if (newLogicalTop != floatLogicalLocation.y()) {
2490 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
2491
2492 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002493 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002494
2495 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2496 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2497
2498 if (childBlock)
2499 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002500 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002501 }
2502
2503 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002504 childBox.setNeedsLayout(MarkOnlyThis);
2505 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002506 }
2507 }
2508
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002509 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002510
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002511 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002512
2513 m_floatingObjects->addPlacedObject(floatingObject);
2514
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002515#if ENABLE(CSS_SHAPES)
2516 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002517 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002518#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002519 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002520 if (childBox.checkForRepaintDuringLayout())
2521 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002522 }
2523 return true;
2524}
2525
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002526void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002527{
2528 positionNewFloats();
2529 // set y position
2530 LayoutUnit newY = 0;
2531 switch (clear) {
2532 case CLEFT:
2533 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2534 break;
2535 case CRIGHT:
2536 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2537 break;
2538 case CBOTH:
2539 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002540 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002541 default:
2542 break;
2543 }
2544 if (height() < newY)
2545 setLogicalHeight(newY);
2546}
2547
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002548LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002549{
2550 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002551 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002552
2553 return fixedOffset;
2554}
2555
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002556LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002557{
2558 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002559 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002560
2561 return fixedOffset;
2562}
2563
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002564LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002565{
2566 if (!m_floatingObjects)
2567 return logicalHeight;
2568
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002569 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2570}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002571
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002572LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2573{
2574 if (!m_floatingObjects)
2575 return logicalHeight;
2576
2577 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002578}
2579
2580LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2581{
2582 if (!m_floatingObjects)
2583 return 0;
2584 LayoutUnit lowestFloatBottom = 0;
2585 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2586 auto end = floatingObjectSet.end();
2587 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2588 FloatingObject* floatingObject = it->get();
2589 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
andersca@apple.com86298632013-11-10 19:32:33 +00002590 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002591 }
2592 return lowestFloatBottom;
2593}
2594
hyatt@apple.com87515262014-09-04 21:20:12 +00002595LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2596{
2597 if (!m_floatingObjects)
2598 return 0;
2599 LayoutUnit lowestFloatBottom = 0;
2600 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2601 auto end = floatingObjectSet.end();
2602 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2603 FloatingObject* floatingObject = it->get();
2604 if (floatingObject->isPlaced() && floatingObject->renderer().style().styleType() == FIRST_LETTER && floatingObject->renderer().style().initialLetterDrop() > 0)
2605 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
2606 }
2607 return lowestFloatBottom;
2608}
2609
weinig@apple.com12840dc2013-10-22 23:59:08 +00002610LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002611{
2612 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002613 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002614 return 0;
2615
weinig@apple.com12840dc2013-10-22 23:59:08 +00002616 LayoutUnit childLogicalTop = child.logicalTop();
2617 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002618 LayoutUnit lowestFloatLogicalBottom = 0;
2619
2620 // Floats that will remain the child's responsibility to paint should factor into its
2621 // overflow.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002622 auto childEnd = child.m_floatingObjects->set().end();
2623 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002624 FloatingObject* floatingObject = childIt->get();
andersca@apple.com86298632013-11-10 19:32:33 +00002625 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002626 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002627 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002628
2629 if (logicalBottom > logicalHeight()) {
2630 // If the object is not in the list, we add it now.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002631 if (!containsFloat(floatingObject->renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002632 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2633 bool shouldPaint = false;
2634
2635 // The nearest enclosing layer always paints the float (so that zindex and stacking
2636 // behaves properly). We always want to propagate the desire to paint the float as
2637 // far out as we can, to the outermost block that overlaps the float, stopping only
2638 // if we hit a self-painting layer boundary.
2639 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2640 floatingObject->setShouldPaint(false);
2641 shouldPaint = true;
2642 }
2643 // We create the floating object list lazily.
2644 if (!m_floatingObjects)
2645 createFloatingObjects();
2646
2647 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2648 }
2649 } else {
2650 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
weinig@apple.com12840dc2013-10-22 23:59:08 +00002651 && floatingObject->renderer().isDescendantOf(&child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002652 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2653 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2654 // layer.
2655 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2656 // it should paint.
2657 floatingObject->setShouldPaint(true);
2658 }
2659
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002660 // 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 +00002661 if (floatingObject->isDescendant())
weinig@apple.com12840dc2013-10-22 23:59:08 +00002662 child.addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002663 }
2664 }
2665 return lowestFloatLogicalBottom;
2666}
2667
weinig@apple.com12840dc2013-10-22 23:59:08 +00002668bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002669{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002670 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002671 return false;
2672
2673 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002674 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002675 if (it == floatingObjectSet.end())
2676 return false;
2677
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002678 return logicalBottomForFloat(it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002679}
2680
hyatt@apple.com21c60802015-04-01 18:10:32 +00002681void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002682{
2683 ASSERT(!avoidsFloats());
2684
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002685 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2686 if (createsNewFormattingContext())
2687 return;
2688
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002689 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2690 if (!prev->m_floatingObjects)
2691 return;
2692
2693 logicalLeftOffset += marginLogicalLeft();
2694
2695 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2696 auto prevEnd = prevSet.end();
2697 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2698 FloatingObject* floatingObject = prevIt->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002699 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002700 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2701 // We create the floating object list lazily.
2702 if (!m_floatingObjects)
2703 createFloatingObjects();
2704
2705 // Applying the child's margin makes no sense in the case where the child was passed in.
2706 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2707 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2708 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2709 // will get applied twice.
2710 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002711 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2712 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002713
2714 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2715 }
2716 }
2717 }
2718}
2719
2720void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2721{
2722 if (!everHadLayout() && !containsFloats())
2723 return;
2724
2725 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2726 setChildNeedsLayout(markParents);
2727
2728 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002729 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002730
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002731 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002732 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2733 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2734 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002735 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002736 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2737 block.setChildNeedsLayout(markParents);
2738 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002739 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002740 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002741 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2742 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002743 }
2744}
2745
2746void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2747{
2748 if (!m_floatingObjects)
2749 return;
2750
2751 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2752 auto end = floatingObjectSet.end();
2753
2754 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
cdumez@apple.come9437792014-10-08 23:33:43 +00002755 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned() || downcast<RenderBlockFlow>(*next).avoidsFloats())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002756 continue;
2757
cdumez@apple.come9437792014-10-08 23:33:43 +00002758 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002759 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002760 RenderBox& floatingBox = (*it)->renderer();
2761 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002762 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002763 if (nextBlock.containsFloat(floatingBox))
2764 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002765 }
2766 }
2767}
2768
weinig@apple.com31324fd2013-10-28 19:22:51 +00002769LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2770{
akling@apple.com827be9c2013-10-29 02:58:43 +00002771 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002772 return point;
2773
2774 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2775 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2776 // case.
2777 if (isHorizontalWritingMode())
2778 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2779 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2780}
2781
weinig@apple.com12840dc2013-10-22 23:59:08 +00002782LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002783{
2784 // There is no need to compute clearance if we have no floats.
2785 if (!containsFloats())
2786 return 0;
2787
2788 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002789 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002790 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002791 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002792 case CNONE:
2793 break;
2794 case CLEFT:
2795 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2796 break;
2797 case CRIGHT:
2798 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2799 break;
2800 case CBOTH:
2801 logicalBottom = lowestFloatLogicalBottom();
2802 break;
2803 }
2804
2805 // 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 +00002806 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002807 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002808 LayoutUnit newLogicalTop = logicalTop;
2809 while (true) {
2810 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2811 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2812 return newLogicalTop - logicalTop;
2813
2814 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002815 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002816 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2817
2818 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002819 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2820 LayoutUnit childOldMarginLeft = child.marginLeft();
2821 LayoutUnit childOldMarginRight = child.marginRight();
2822 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002823
weinig@apple.com12840dc2013-10-22 23:59:08 +00002824 child.setLogicalTop(newLogicalTop);
2825 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002826 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002827 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002828 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2829
weinig@apple.com12840dc2013-10-22 23:59:08 +00002830 child.setLogicalTop(childOldLogicalTop);
2831 child.setLogicalWidth(childOldLogicalWidth);
2832 child.setMarginLeft(childOldMarginLeft);
2833 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002834
2835 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2836 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2837 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2838 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2839 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002840 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002841 return newLogicalTop - logicalTop;
2842 }
2843
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002844 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002845 ASSERT(newLogicalTop >= logicalTop);
2846 if (newLogicalTop < logicalTop)
2847 break;
2848 }
2849 ASSERT_NOT_REACHED();
2850 }
2851 return result;
2852}
2853
2854bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2855{
2856 if (!m_floatingObjects)
2857 return false;
2858
2859 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002860 if (is<RenderView>(*this))
2861 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002862
2863 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2864 auto begin = floatingObjectSet.begin();
2865 for (auto it = floatingObjectSet.end(); it != begin;) {
2866 --it;
2867 FloatingObject* floatingObject = it->get();
2868 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2869 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2870 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2871 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2872 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2873 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2874 return true;
2875 }
2876 }
2877 }
2878
2879 return false;
2880}
2881
weinig@apple.com611b9292013-10-20 22:57:54 +00002882bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2883{
2884 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002885
darin@apple.come1be6ca2014-04-28 04:19:10 +00002886 if (auto simpleLineLayout = this->simpleLineLayout())
2887 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002888
weinig@apple.com611b9292013-10-20 22:57:54 +00002889 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2890}
2891
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002892void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2893{
akling@apple.com827be9c2013-10-29 02:58:43 +00002894 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002895 return;
2896
2897 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2898 // for either overflow or translations via relative positioning.
2899 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002900 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2901
weinig@apple.com611b9292013-10-20 22:57:54 +00002902 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
2903 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002904 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002905 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002906 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002907 }
2908 } else {
2909 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2910 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002911 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2912 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002913 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002914 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002915 left = std::min(left, x + obj->x());
2916 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002917 }
2918 }
2919 }
2920 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002921
2922 if (m_floatingObjects) {
2923 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2924 auto end = floatingObjectSet.end();
2925 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2926 FloatingObject* r = it->get();
2927 // Only examine the object if our m_shouldPaint flag is set.
2928 if (r->shouldPaint()) {
2929 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2930 LayoutUnit floatRight = floatLeft + r->renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002931 left = std::min(left, floatLeft);
2932 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002933 }
2934 }
2935 }
2936}
2937
2938void RenderBlockFlow::fitBorderToLinesIfNeeded()
2939{
akling@apple.com827be9c2013-10-29 02:58:43 +00002940 if (style().borderFit() == BorderFitBorder || hasOverrideWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002941 return;
2942
2943 // Walk any normal flow lines to snugly fit.
2944 LayoutUnit left = LayoutUnit::max();
2945 LayoutUnit right = LayoutUnit::min();
2946 LayoutUnit oldWidth = contentWidth();
2947 adjustForBorderFit(0, left, right);
2948
2949 // Clamp to our existing edges. We can never grow. We only shrink.
2950 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2951 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002952 left = std::min(rightEdge, std::max(leftEdge, left));
2953 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002954
2955 LayoutUnit newContentWidth = right - left;
2956 if (newContentWidth == oldWidth)
2957 return;
2958
2959 setOverrideLogicalContentWidth(newContentWidth);
2960 layoutBlock(false);
2961 clearOverrideLogicalContentWidth();
2962}
2963
2964void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
2965{
2966 if (logicalTop >= logicalBottom)
2967 return;
2968
antti@apple.combe9d3e12014-05-11 09:42:47 +00002969 // Floats currently affect the choice whether to use simple line layout path.
2970 if (m_simpleLineLayout) {
2971 invalidateLineLayoutPath();
2972 return;
2973 }
2974
weinig@apple.com611b9292013-10-20 22:57:54 +00002975 RootInlineBox* lowestDirtyLine = lastRootBox();
2976 RootInlineBox* afterLowest = lowestDirtyLine;
2977 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
2978 afterLowest = lowestDirtyLine;
2979 lowestDirtyLine = lowestDirtyLine->prevRootBox();
2980 }
2981
2982 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
2983 afterLowest->markDirty();
2984 afterLowest = afterLowest->prevRootBox();
2985 }
2986}
2987
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002988Optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00002989{
2990 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002991 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00002992
2993 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00002994 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00002995
antti@apple.com940f5872013-10-24 20:31:11 +00002996 if (!hasLines())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00002997 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00002998
darin@apple.come1be6ca2014-04-28 04:19:10 +00002999 if (auto simpleLineLayout = this->simpleLineLayout())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003000 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003001
akling@apple.comee3c8df2013-11-06 08:09:44 +00003002 ASSERT(firstRootBox());
3003 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003004}
3005
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003006Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003007{
3008 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003009 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003010
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003011 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3012 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3013 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003014 if (!childrenInline()) {
3015 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3016 if (!inlineBlockBaseline)
3017 return inlineBlockBaseline;
3018 lastBaseline = inlineBlockBaseline.value();
3019 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003020 if (!hasLines()) {
3021 if (!hasLineIfEmpty())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003022 return Optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003023 const auto& fontMetrics = firstLineStyle().fontMetrics();
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003024 return Optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003025 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003026 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003027 }
3028
3029 if (auto simpleLineLayout = this->simpleLineLayout())
3030 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3031 else {
3032 bool isFirstLine = lastRootBox() == firstRootBox();
3033 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3034 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3035 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003036 }
3037 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3038 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3039 // enough with the spec to not cause tons of breakages).
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003040 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003041}
3042
weinig@apple.com12840dc2013-10-22 23:59:08 +00003043GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003044 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3045{
antti@apple.comfea51992013-10-28 13:39:23 +00003046 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003047
weinig@apple.com611b9292013-10-20 22:57:54 +00003048 GapRects result;
3049
3050 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3051
antti@apple.com0e632aa2013-10-22 21:03:38 +00003052 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003053 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003054 // 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 +00003055 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3056 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3057 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3058 }
3059 return result;
3060 }
3061
3062 RootInlineBox* lastSelectedLine = 0;
3063 RootInlineBox* curr;
3064 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3065
3066 // Now paint the gaps for the lines.
3067 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3068 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3069 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3070
3071 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003072 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003073 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3074
3075 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3076 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003077 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003078 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3079 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3080 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3081
3082 lastSelectedLine = curr;
3083 }
3084
3085 if (containsStart && !lastSelectedLine)
3086 // VisibleSelection must start just after our last line.
3087 lastSelectedLine = lastRootBox();
3088
3089 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003090 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003091 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3092 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3093 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3094 }
3095 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003096}
3097
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003098void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3099{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003100 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003101 return;
3102
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003103 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3104 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003105 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003106 flowFragment->initializeStyle();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003107 setRenderNamedFlowFragment(flowFragment);
3108 addChild(renderNamedFlowFragment());
3109 }
3110}
3111
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003112bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3113{
3114 // A block without floats or that expands to enclose them won't need a relayout
3115 // after a region range change. There is no overflow content needing relayout
3116 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003117 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003118 return false;
3119
3120 return true;
3121}
3122
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003123bool RenderBlockFlow::canHaveChildren() const
3124{
3125 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3126}
3127
3128bool RenderBlockFlow::canHaveGeneratedChildren() const
3129{
3130 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3131}
3132
3133bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3134{
3135 if (!isRenderNamedFlowFragmentContainer())
3136 return false;
3137
3138 return hasRelativeLogicalHeight() && !isRenderView();
3139}
3140
3141void RenderBlockFlow::updateLogicalHeight()
3142{
3143 RenderBlock::updateLogicalHeight();
3144
abucur@adobe.comfad53712014-05-06 17:30:40 +00003145 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003146 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003147 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3148 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003149}
3150
3151void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3152{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003153 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003154 if (rareData.m_renderNamedFlowFragment)
3155 rareData.m_renderNamedFlowFragment->destroy();
3156 rareData.m_renderNamedFlowFragment = flowFragment;
3157}
3158
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003159void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3160{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003161 if (flowThread || hasRareBlockFlowData()) {
3162 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3163 rareData.m_multiColumnFlowThread = flowThread;
3164 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003165}
3166
akling@apple.com525dae62014-01-03 20:22:09 +00003167static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003168{
akling@apple.com38f0a652014-02-06 21:24:17 +00003169 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003170}
3171
3172RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3173{
3174 ASSERT(i >= 0);
3175
akling@apple.com827be9c2013-10-29 02:58:43 +00003176 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003177 return nullptr;
3178
3179 if (childrenInline()) {
3180 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3181 if (!i--)
3182 return box;
3183 }
akling@apple.com525dae62014-01-03 20:22:09 +00003184 return nullptr;
3185 }
3186
3187 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3188 if (!shouldCheckLines(blockFlow))
3189 continue;
3190 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3191 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003192 }
3193
3194 return nullptr;
3195}
3196
3197int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3198{
akling@apple.com827be9c2013-10-29 02:58:43 +00003199 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003200 return 0;
3201
3202 int count = 0;
3203
3204 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003205 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003206 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003207 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003208 }
weinig@apple.com17140912013-10-19 19:55:40 +00003209 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3210 count++;
3211 if (box == stopRootInlineBox) {
3212 if (found)
3213 *found = true;
3214 break;
3215 }
3216 }
akling@apple.com525dae62014-01-03 20:22:09 +00003217 return count;
3218 }
3219
3220 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3221 if (!shouldCheckLines(blockFlow))
3222 continue;
3223 bool recursiveFound = false;
3224 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3225 if (recursiveFound) {
3226 if (found)
3227 *found = true;
3228 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003229 }
3230 }
3231
3232 return count;
3233}
3234
3235static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3236{
akling@apple.com827be9c2013-10-29 02:58:43 +00003237 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003238 return -1;
3239
3240 if (block.childrenInline()) {
3241 for (auto box = block.firstRootBox(); box; box = box->nextRootBox()) {
3242 if (++count == lineCount)
3243 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3244 }
3245 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003246 RenderBox* normalFlowChildWithoutLines = nullptr;
weinig@apple.com17140912013-10-19 19:55:40 +00003247 for (auto obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003248 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3249 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003250 if (result != -1)
3251 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003252 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003253 normalFlowChildWithoutLines = obj;
3254 }
3255 if (normalFlowChildWithoutLines && !lineCount)
3256 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3257 }
3258
3259 return -1;
3260}
3261
3262int RenderBlockFlow::heightForLineCount(int lineCount)
3263{
3264 int count = 0;
3265 return getHeightForLineCount(*this, lineCount, true, count);
3266}
3267
3268void RenderBlockFlow::clearTruncation()
3269{
akling@apple.com827be9c2013-10-29 02:58:43 +00003270 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003271 return;
3272
3273 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003274 ensureLineBoxes();
3275
weinig@apple.com17140912013-10-19 19:55:40 +00003276 setHasMarkupTruncation(false);
3277 for (auto box = firstRootBox(); box; box = box->nextRootBox())
3278 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003279 return;
3280 }
3281
3282 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3283 if (shouldCheckLines(blockFlow))
3284 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003285 }
3286}
3287
weinig@apple.com3f23b382013-10-19 20:26:58 +00003288bool RenderBlockFlow::containsNonZeroBidiLevel() const
3289{
3290 for (auto root = firstRootBox(); root; root = root->nextRootBox()) {
3291 for (auto box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
3292 if (box->bidiLevel())
3293 return true;
3294 }
3295 }
3296 return false;
3297}
3298
weinig@apple.com611b9292013-10-20 22:57:54 +00003299Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3300{
3301 if (!box)
3302 return Position();
3303
3304 if (!box->renderer().nonPseudoNode())
3305 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3306
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003307 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003308 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3309
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003310 auto& textBox = downcast<InlineTextBox>(*box);
3311 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003312}
3313
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003314VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003315{
3316 ASSERT(childrenInline());
3317
antti@apple.com940f5872013-10-24 20:31:11 +00003318 ensureLineBoxes();
3319
weinig@apple.com611b9292013-10-20 22:57:54 +00003320 if (!firstRootBox())
3321 return createVisiblePosition(0, DOWNSTREAM);
3322
akling@apple.com827be9c2013-10-29 02:58:43 +00003323 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3324 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003325
3326 // look for the closest line box in the root box which is at the passed-in y coordinate
3327 InlineBox* closestBox = 0;
3328 RootInlineBox* firstRootBoxWithChildren = 0;
3329 RootInlineBox* lastRootBoxWithChildren = 0;
3330 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003331 if (region && root->containingRegion() != region)
3332 continue;
3333
weinig@apple.com611b9292013-10-20 22:57:54 +00003334 if (!root->firstLeafChild())
3335 continue;
3336 if (!firstRootBoxWithChildren)
3337 firstRootBoxWithChildren = root;
3338
3339 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3340 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3341 break;
3342
3343 lastRootBoxWithChildren = root;
3344
3345 // check if this root line box is located at this y coordinate
3346 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3347 if (linesAreFlipped) {
3348 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3349 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3350 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3351
3352 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3353 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3354 continue;
3355 }
3356 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3357 if (closestBox)
3358 break;
3359 }
3360 }
3361
3362 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3363
3364 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3365 // y coordinate is below last root line box, pretend we hit it
3366 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3367 }
3368
3369 if (closestBox) {
3370 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003371 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003372 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3373 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3374 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3375 if (box->isLineBreak()) {
3376 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3377 box = newBox;
3378 }
3379 // y coordinate is above first root line box, so return the start of the first
3380 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3381 }
3382 }
3383
3384 // pass the box a top position that is inside it
3385 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3386 if (!isHorizontalWritingMode())
3387 point = point.transposedPoint();
3388 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003389 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003390 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003391 }
3392
3393 if (lastRootBoxWithChildren) {
3394 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3395 ASSERT(moveCaretToBoundary);
3396 InlineBox* logicallyLastBox;
3397 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3398 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3399 }
3400
3401 // Can't reach this. We have a root line box, but it has no kids.
3402 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3403 // seems to hit this code path.
3404 return createVisiblePosition(0, DOWNSTREAM);
3405}
3406
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003407VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003408{
3409 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003410 return fragment->positionForPoint(point, region);
3411 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003412}
3413
3414
weinig@apple.com611b9292013-10-20 22:57:54 +00003415void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3416{
antti@apple.com940f5872013-10-24 20:31:11 +00003417 ASSERT(childrenInline());
3418
3419 ensureLineBoxes();
3420
weinig@apple.com611b9292013-10-20 22:57:54 +00003421 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003422 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3423 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003424 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3425 if (!rect.isEmpty())
zalan@apple.com376339c2014-08-28 04:24:31 +00003426 rects.append(snappedIntRect(rect));
weinig@apple.com611b9292013-10-20 22:57:54 +00003427 }
3428}
3429
3430void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3431{
3432 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003433
darin@apple.come1be6ca2014-04-28 04:19:10 +00003434 if (auto simpleLineLayout = this->simpleLineLayout()) {
3435 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003436 return;
3437 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003438 m_lineBoxes.paint(this, paintInfo, paintOffset);
3439}
3440
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003441bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003442{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003443 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003444 return false;
3445
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003446 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003447 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3448
3449 bool needsRelayout;
3450 bool neededRelayout = false;
3451 bool firstPass = true;
3452 do {
3453 // Column heights may change here because of balancing. We may have to do multiple layout
3454 // passes, depending on how the contents is fitted to the changed column heights. In most
3455 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3456 // passes than that, though, but the number of retries should not exceed the number of
3457 // columns, unless we have a bug.
3458 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003459 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3460 if (multicolSet->recalculateColumnHeight(firstPass))
3461 needsRelayout = true;
3462 if (needsRelayout) {
3463 // Once a column set gets a new column height, that column set and all successive column
3464 // sets need to be laid out over again, since their logical top will be affected by
3465 // this, and therefore their column heights may change as well, at least if the multicol
3466 // height is constrained.
3467 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003468 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003469 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003470 if (needsRelayout) {
3471 // Layout again. Column balancing resulted in a new height.
3472 neededRelayout = true;
3473 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3474 setChildNeedsLayout(MarkOnlyThis);
3475 if (firstPass)
3476 statePusher.pop();
3477 layoutBlock(false);
3478 }
3479 firstPass = false;
3480 } while (needsRelayout);
3481
3482 multiColumnFlowThread()->setInBalancingPass(false);
3483
3484 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003485}
3486
antti@apple.com940f5872013-10-24 20:31:11 +00003487bool RenderBlockFlow::hasLines() const
3488{
3489 ASSERT(childrenInline());
3490
darin@apple.come1be6ca2014-04-28 04:19:10 +00003491 if (auto simpleLineLayout = this->simpleLineLayout())
3492 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003493
3494 return lineBoxes().firstLineBox();
3495}
3496
antti@apple.com9e891c82014-05-22 06:12:34 +00003497void RenderBlockFlow::invalidateLineLayoutPath()
3498{
akling@apple.coma12fee22015-02-01 02:58:13 +00003499 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003500 case UndeterminedPath:
3501 case ForceLineBoxesPath:
3502 ASSERT(!m_simpleLineLayout);
3503 return;
3504 case LineBoxesPath:
3505 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003506 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003507 return;
3508 case SimpleLinesPath:
3509 // The simple line layout may have become invalid.
3510 m_simpleLineLayout = nullptr;
3511 setNeedsLayout();
akling@apple.coma12fee22015-02-01 02:58:13 +00003512 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003513 return;
3514 }
3515 ASSERT_NOT_REACHED();
3516}
3517
zalan@apple.come37da962014-12-11 03:29:29 +00003518void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003519{
zalan@apple.come37da962014-12-11 03:29:29 +00003520 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3521 if (needsLayout) {
3522 deleteLineBoxesBeforeSimpleLineLayout();
3523 m_simpleLineLayout = SimpleLineLayout::create(*this);
3524 }
antti@apple.com940f5872013-10-24 20:31:11 +00003525 ASSERT(!m_lineBoxes.firstLineBox());
3526
antti@apple.comfea51992013-10-28 13:39:23 +00003527 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003528 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003529 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003530 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003531 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3532}
3533
3534void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3535{
akling@apple.coma12fee22015-02-01 02:58:13 +00003536 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003537 lineBoxes().deleteLineBoxes();
zalan@apple.com29a2eb62014-11-20 18:11:07 +00003538 ASSERT(!childrenOfType<RenderElement>(*this).first());
3539 for (auto& textRenderer : childrenOfType<RenderText>(*this))
3540 textRenderer.deleteLineBoxesBeforeSimpleLineLayout();
antti@apple.com940f5872013-10-24 20:31:11 +00003541}
3542
3543void RenderBlockFlow::ensureLineBoxes()
3544{
akling@apple.coma12fee22015-02-01 02:58:13 +00003545 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003546 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003547 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003548 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003549
3550#if !ASSERT_DISABLED
3551 LayoutUnit oldHeight = logicalHeight();
3552#endif
3553 bool didNeedLayout = needsLayout();
3554
3555 bool relayoutChildren = false;
3556 LayoutUnit repaintLogicalTop;
3557 LayoutUnit repaintLogicalBottom;
3558 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3559
3560 updateLogicalHeight();
3561 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3562
3563 if (!didNeedLayout)
3564 clearNeedsLayout();
3565}
3566
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003567#if ENABLE(TREE_DEBUGGING)
zalan@apple.comfac337f2014-08-29 17:55:34 +00003568void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003569{
weinig@apple.com611b9292013-10-20 22:57:54 +00003570 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003571 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003572
3573 if (auto simpleLineLayout = this->simpleLineLayout())
3574 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003575}
3576#endif
3577
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003578RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3579{
3580 if (hasRareBlockFlowData())
3581 return *m_rareBlockFlowData;
3582 materializeRareBlockFlowData();
3583 return *m_rareBlockFlowData;
3584}
3585
3586void RenderBlockFlow::materializeRareBlockFlowData()
3587{
3588 ASSERT(!hasRareBlockFlowData());
3589 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3590}
3591
aestes@apple.com6751d842014-01-12 02:51:25 +00003592#if ENABLE(IOS_TEXT_AUTOSIZING)
3593inline static bool isVisibleRenderText(RenderObject* renderer)
3594{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003595 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003596 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003597 RenderText& renderText = downcast<RenderText>(*renderer);
3598 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003599}
3600
3601inline static bool resizeTextPermitted(RenderObject* render)
3602{
3603 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3604 auto renderer = render->parent();
3605 while (renderer) {
3606 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003607 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003608 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003609 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003610 }
3611 renderer = renderer->parent();
3612 }
3613 return true;
3614}
3615
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003616int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003617{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003618 if (style().visibility() != VISIBLE)
3619 return 0;
3620 if (childrenInline())
3621 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003622 // Only descend into list items.
3623 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003624 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3625 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003626 return count;
3627}
3628
3629static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3630{
3631 if (!render->isRenderBlock())
3632 return true;
3633 if (render->isListItem())
3634 return render->style().height().type() != Fixed;
3635 return false;
3636}
3637
3638// For now, we auto size single lines of text the same as multiple lines.
3639// We've been experimenting with low values for single lines of text.
3640static inline float oneLineTextMultiplier(float specifiedSize)
3641{
3642 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3643}
3644
3645static inline float textMultiplier(float specifiedSize)
3646{
3647 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3648}
3649
3650void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3651{
3652 // Don't do any work if the block is smaller than the visible area.
3653 if (visibleWidth >= width())
3654 return;
3655
3656 unsigned lineCount;
3657 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003658 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003659 if (!count)
3660 lineCount = NO_LINE;
3661 else if (count == 1)
3662 lineCount = ONE_LINE;
3663 else
3664 lineCount = MULTI_LINE;
3665 } else
3666 lineCount = m_lineCountForTextAutosizing;
3667
3668 ASSERT(lineCount != NOT_SET);
3669 if (lineCount == NO_LINE)
3670 return;
3671
3672 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3673 float scale = visibleWidth / actualWidth;
3674 float minFontSize = roundf(size / scale);
3675
3676 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3677 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003678 RenderText& text = downcast<RenderText>(*descendent);
3679 RenderStyle& oldStyle = text.style();
aestes@apple.com6751d842014-01-12 02:51:25 +00003680 FontDescription fontDescription = oldStyle.fontDescription();
3681 float specifiedSize = fontDescription.specifiedSize();
3682 float scaledSize = roundf(specifiedSize * scale);
3683 if (scaledSize > 0 && scaledSize < minFontSize) {
3684 // 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.
3685 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3686 if (m_lineCountForTextAutosizing == NOT_SET)
3687 m_lineCountForTextAutosizing = lineCount;
3688 if (m_widthForTextAutosizing == -1)
3689 m_widthForTextAutosizing = actualWidth;
3690
3691 float candidateNewSize = 0;
3692 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3693 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003694 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3695 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003696 }
3697 }
3698 }
3699}
3700#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3701
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003702RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3703{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003704 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3705 if (!flowThread)
3706 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003707
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003708 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003709
3710 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003711 flowThread->setChildNeedsLayout(MarkOnlyThis);
3712
3713 if (flowThread->needsLayout()) {
3714 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3715 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3716
3717 flowThread->invalidateRegions();
3718 flowThread->setNeedsHeightsRecalculation(true);
3719 flowThread->layout();
3720 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003721 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3722 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3723 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3724 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3725 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3726 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3727 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3728 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003729 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003730 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003731 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003732
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003733 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003734}
3735
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003736void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3737{
3738 if (multiColumnFlowThread())
3739 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003740 if (beforeChild) {
3741 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3742 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3743 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003744 RenderBlock::addChild(newChild, beforeChild);
3745}
3746
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003747void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003748{
3749 if (!documentBeingDestroyed()) {
3750 RenderFlowThread* flowThread = multiColumnFlowThread();
3751 if (flowThread && flowThread != &oldChild)
3752 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3753 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003754 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003755}
3756
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003757void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003758{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003759 // If we don't use columns or flow threads, then bail.
3760 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003761 return;
3762
3763 // 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 +00003764 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3765 LogicalExtentComputedValues computedValues;
3766 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3767 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003768 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003769 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003770 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3771 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003772 } else if (is<RenderFlowThread>(*this)) {
3773 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003774
3775 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3776 // is known. The page logical height thing in LayoutState is meaningless for flow
3777 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3778 // thread), but as long as it is used universally as a means to determine whether page
3779 // height is known or not, we need this. Page height is unknown when column balancing is
3780 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3781 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3782 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3783 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003784 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003785
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003786 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003787 }
3788}
3789
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003790bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3791{
3792 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3793 // in the RenderView instead.
3794 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isRoot() || isBody());
3795
3796 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3797}
3798
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003799void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3800{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003801 bool destroyColumns = !requiresColumns(count);
3802 if (destroyColumns) {
3803 if (multiColumnFlowThread())
3804 destroyMultiColumnFlowThread();
3805 } else {
3806 if (!multiColumnFlowThread())
3807 createMultiColumnFlowThread();
3808 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003809 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3810 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003811 }
3812}
3813
cdumez@apple.com78141732014-11-04 23:00:48 +00003814void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003815{
hyatt@apple.com86919862014-01-27 16:27:45 +00003816 if (!multiColumnFlowThread())
3817 return;
3818
3819 bool needsLayout = false;
3820 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003821 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003822 if (oldProgressionIsInline != newProgressionIsInline) {
3823 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3824 needsLayout = true;
3825 }
3826
3827 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003828 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003829 if (oldProgressionIsReversed != newProgressionIsReversed) {
3830 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3831 needsLayout = true;
3832 }
3833
3834 if (needsLayout)
3835 setNeedsLayoutAndPrefWidthsRecalc();
3836}
3837
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003838LayoutUnit RenderBlockFlow::computedColumnWidth() const
3839{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003840 if (multiColumnFlowThread())
3841 return multiColumnFlowThread()->computedColumnWidth();
3842 return contentLogicalWidth();
3843}
3844
3845unsigned RenderBlockFlow::computedColumnCount() const
3846{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003847 if (multiColumnFlowThread())
3848 return multiColumnFlowThread()->computedColumnCount();
3849
3850 return 1;
3851}
3852
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003853bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3854{
3855 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3856 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3857 return hasTopOverflow;
3858
3859 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3860 hasTopOverflow = !hasTopOverflow;
3861
3862 return hasTopOverflow;
3863}
3864
3865bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3866{
3867 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3868 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3869 return hasLeftOverflow;
3870
3871 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3872 hasLeftOverflow = !hasLeftOverflow;
3873
3874 return hasLeftOverflow;
3875}
3876
zalan@apple.comac6956c2014-09-05 14:18:06 +00003877struct InlineMinMaxIterator {
3878/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3879 inline min/max width calculations. Note the following about the way it walks:
3880 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3881 (2) We do not drill into the children of floats or replaced elements, since you can't break
3882 in the middle of such an element.
3883 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3884 distinct borders/margin/padding that contribute to the min/max width.
3885*/
3886 const RenderBlockFlow& parent;
3887 RenderObject* current;
3888 bool endOfInline;
3889 bool initial;
3890
3891 InlineMinMaxIterator(const RenderBlockFlow& p)
3892 : parent(p)
3893 , current(nullptr)
3894 , endOfInline(false)
3895 , initial(true)
3896 { }
3897
3898 RenderObject* next();
3899};
3900
3901RenderObject* InlineMinMaxIterator::next()
3902{
3903 RenderObject* result = nullptr;
3904 bool oldEndOfInline = endOfInline;
3905 endOfInline = false;
3906 do {
3907 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3908 result = current->firstChildSlow();
3909 else if (initial) {
3910 result = parent.firstChild();
3911 initial = false;
3912 }
3913
3914 if (!result) {
3915 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3916 if (!oldEndOfInline && current && current->isRenderInline()) {
3917 result = current;
3918 endOfInline = true;
3919 break;
3920 }
3921
3922 while (current && current != &parent) {
3923 result = current->nextSibling();
3924 if (result)
3925 break;
3926 current = current->parent();
3927 if (current && current != &parent && current->isRenderInline()) {
3928 result = current;
3929 endOfInline = true;
3930 break;
3931 }
3932 }
3933 }
3934
3935 if (!result)
3936 break;
3937
3938 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3939 break;
3940
3941 current = result;
3942 result = nullptr;
3943 } while (current || current == &parent);
3944 // Update our position.
3945 current = result;
3946 return result;
3947}
3948
3949static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3950{
3951 if (cssUnit.type() != Auto)
3952 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
3953 return 0;
3954}
3955
3956static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
3957{
3958 const RenderStyle& childStyle = child.style();
3959 if (endOfInline) {
3960 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
3961 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
3962 child.borderEnd();
3963 }
3964 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
3965 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
3966 child.borderStart();
3967}
3968
3969static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
3970{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003971 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00003972 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003973 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00003974 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00003975 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003976 float spaceWidth = font.width(RenderBlock::constructTextRun(&renderText, font, &space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00003977 inlineMax -= spaceWidth + font.wordSpacing();
3978 if (inlineMin > inlineMax)
3979 inlineMin = inlineMax;
3980 }
3981}
3982
3983static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
3984{
3985 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
3986}
3987
3988void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3989{
3990 float inlineMax = 0;
3991 float inlineMin = 0;
3992
3993 const RenderStyle& styleToUse = style();
3994 RenderBlock* containingBlock = this->containingBlock();
3995 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
3996
3997 // If we are at the start of a line, we want to ignore all white-space.
3998 // Also strip spaces if we previously had text that ended in a trailing space.
3999 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004000 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004001
4002 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4003 // very specific cirucumstances (in order to match common WinIE renderings).
4004 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4005 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4006
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004007 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004008
4009 InlineMinMaxIterator childIterator(*this);
4010
4011 // Only gets added to the max preffered width once.
4012 bool addedTextIndent = false;
4013 // Signals the text indent was more negative than the min preferred width
4014 bool hasRemainingNegativeTextIndent = false;
4015
4016 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4017 RenderObject* prevFloat = 0;
4018 bool isPrevChildInlineFlow = false;
4019 bool shouldBreakLineAfterText = false;
4020 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004021 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004022 child->style().autoWrap();
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004023 bool isAnonymousInlineBlock = child->isAnonymousInlineBlock();
4024
zalan@apple.comac6956c2014-09-05 14:18:06 +00004025 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004026 // Step One: determine whether or not we need to terminate our current line.
4027 // Each discrete chunk can become the new min-width, if it is the widest chunk
4028 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004029
4030 // Children fall into three categories:
4031 // (1) An inline flow object. These objects always have a min/max of 0,
4032 // and are included in the iteration solely so that their margins can
4033 // be added in.
4034 //
4035 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4036 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004037 // we need to break the current line, and then add in our own margins and min/max
4038 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004039 //
4040 // (3) A text object. Text runs can have breakable characters at the start,
4041 // the middle or the end. They may also lose whitespace off the front if
4042 // we're already ignoring whitespace. In order to compute accurate min-width
4043 // information, we need three pieces of information.
4044 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4045 // starts with whitespace.
4046 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4047 // ends with whitespace.
4048 // (c) the min/max width of the string (trimmed for whitespace).
4049 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004050 // If the text string starts with whitespace, then we need to terminate our current line
4051 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004052 //
4053 // If the text string has a breakable character in the middle, but didn't start
4054 // with whitespace, then we add the width of the first non-breakable run and
4055 // then end the current line. We then need to use the intermediate min/max width
4056 // values (if any of them are larger than our current min/max). We then look at
4057 // the width of the last non-breakable run and use that to start a new line
4058 // (unless we end in whitespace).
4059 const RenderStyle& childStyle = child->style();
4060 float childMin = 0;
4061 float childMax = 0;
4062
4063 if (!child->isText()) {
4064 if (child->isLineBreakOpportunity()) {
4065 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4066 inlineMin = 0;
4067 continue;
4068 }
4069 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004070 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004071 // Add in padding/border/margin from the appropriate side of
4072 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004073 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004074 childMin += bpm;
4075 childMax += bpm;
4076
4077 inlineMin += childMin;
4078 inlineMax += childMax;
4079
4080 child->setPreferredLogicalWidthsDirty(false);
4081 } else {
4082 // Inline replaced elts add in their margins to their min/max values.
4083 LayoutUnit margins = 0;
4084 Length startMargin = childStyle.marginStart();
4085 Length endMargin = childStyle.marginEnd();
4086 if (startMargin.isFixed())
4087 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4088 if (endMargin.isFixed())
4089 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4090 childMin += margins.ceilToFloat();
4091 childMax += margins.ceilToFloat();
4092 }
4093 }
4094
cdumez@apple.comf8022152014-10-15 00:29:51 +00004095 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004096 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004097 // Terminate the current line as far as minwidth is concerned.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004098 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4099 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4100
4101 bool clearPreviousFloat;
4102 if (child->isFloating()) {
4103 clearPreviousFloat = (prevFloat
4104 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4105 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4106 prevFloat = child;
4107 } else
4108 clearPreviousFloat = false;
4109
4110 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004111 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) || isAnonymousInlineBlock) {
4112 if (child->isAnonymousInlineBlock() && styleToUse.collapseWhiteSpace())
4113 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004114 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4115 inlineMin = 0;
4116 }
4117
4118 // If we're supposed to clear the previous float, then terminate maxwidth as well.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004119 if (clearPreviousFloat || isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004120 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4121 inlineMax = 0;
4122 }
4123
4124 // Add in text-indent. This is added in only once.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004125 if (!addedTextIndent && !child->isFloating() && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004126 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4127 childMin += ceiledIndent;
4128 childMax += ceiledIndent;
4129
4130 if (childMin < 0)
4131 textIndent = LayoutUnit::fromFloatCeil(childMin);
4132 else
4133 addedTextIndent = true;
4134 }
4135
4136 // Add our width to the max.
4137 inlineMax += std::max<float>(0, childMax);
4138
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004139 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004140 if (child->isFloating())
4141 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4142 else
4143 inlineMin += childMin;
4144 } else {
4145 // Now check our line.
4146 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4147
4148 // Now start a new line.
4149 inlineMin = 0;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004150
4151 if (child->isAnonymousInlineBlock()) {
4152 // Terminate max width as well.
4153 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4154 inlineMax = 0;
4155 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004156 }
4157
4158 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4159 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4160 inlineMin = 0;
4161 }
4162
4163 // We are no longer stripping whitespace at the start of a line.
4164 if (!child->isFloating()) {
4165 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004166 trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004167 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004168 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004169 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004170 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004171
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004172 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4173 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004174
4175 // Determine if we have a breakable character. Pass in
4176 // whether or not we should ignore any spaces at the front
4177 // of the string. If those are going to be stripped out,
4178 // then they shouldn't be considered in the breakable char
4179 // check.
4180 bool hasBreakableChar, hasBreak;
4181 float beginMin, endMin;
4182 bool beginWS, endWS;
4183 float beginMax, endMax;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004184 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004185 hasBreakableChar, hasBreak, beginMax, endMax,
4186 childMin, childMax, stripFrontSpaces);
4187
4188 // This text object will not be rendered, but it may still provide a breaking opportunity.
4189 if (!hasBreak && !childMax) {
4190 if (autoWrap && (beginWS || endWS)) {
4191 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4192 inlineMin = 0;
4193 }
4194 continue;
4195 }
4196
4197 if (stripFrontSpaces)
4198 trailingSpaceChild = child;
4199 else
4200 trailingSpaceChild = 0;
4201
4202 // Add in text-indent. This is added in only once.
4203 float ti = 0;
4204 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4205 ti = textIndent.ceilToFloat();
4206 childMin += ti;
4207 beginMin += ti;
4208
4209 // It the text indent negative and larger than the child minimum, we re-use the remainder
4210 // in future minimum calculations, but using the negative value again on the maximum
4211 // will lead to under-counting the max pref width.
4212 if (!addedTextIndent) {
4213 childMax += ti;
4214 beginMax += ti;
4215 addedTextIndent = true;
4216 }
4217
4218 if (childMin < 0) {
4219 textIndent = childMin;
4220 hasRemainingNegativeTextIndent = true;
4221 }
4222 }
4223
4224 // If we have no breakable characters at all,
4225 // then this is the easy case. We add ourselves to the current
4226 // min and max and continue.
4227 if (!hasBreakableChar)
4228 inlineMin += childMin;
4229 else {
4230 // We have a breakable character. Now we need to know if
4231 // we start and end with whitespace.
4232 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004233 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004234 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4235 } else {
4236 inlineMin += beginMin;
4237 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4238 childMin -= ti;
4239 }
4240
4241 inlineMin = childMin;
4242
4243 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004244 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004245 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4246 inlineMin = 0;
4247 shouldBreakLineAfterText = false;
4248 } else {
4249 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4250 inlineMin = endMin;
4251 shouldBreakLineAfterText = true;
4252 }
4253 }
4254
4255 if (hasBreak) {
4256 inlineMax += beginMax;
4257 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4258 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4259 inlineMax = endMax;
4260 addedTextIndent = true;
4261 } else
4262 inlineMax += std::max<float>(0, childMax);
4263 }
4264
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004265 // Ignore spaces after a list marker and also after an anonymous inline block.
4266 if (child->isListMarker() || isAnonymousInlineBlock)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004267 stripFrontSpaces = true;
4268 } else {
4269 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4270 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4271 inlineMin = inlineMax = 0;
4272 stripFrontSpaces = true;
4273 trailingSpaceChild = 0;
4274 addedTextIndent = true;
4275 }
4276
4277 if (!child->isText() && child->isRenderInline())
4278 isPrevChildInlineFlow = true;
4279 else
4280 isPrevChildInlineFlow = false;
4281
4282 oldAutoWrap = autoWrap;
4283 }
4284
4285 if (styleToUse.collapseWhiteSpace())
4286 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4287
4288 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4289 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4290}
4291
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004292}
4293// namespace WebCore