blob: 03f756c57dd99917a174c525732f6b2588c0ff20 [file] [log] [blame]
hyatt@apple.com5388e672013-09-06 20:54:47 +00001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
bfulgham@apple.comb5953432015-02-13 21:56:01 +00005 * Copyright (C) 2003-2015 Apple Inc. All rights reserved.
hyatt@apple.com5388e672013-09-06 20:54:47 +00006 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "RenderBlockFlow.h"
26
weinig@apple.com611b9292013-10-20 22:57:54 +000027#include "Editor.h"
bjonesbe@adobe.com67478092013-09-09 22:18:17 +000028#include "FloatingObjects.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000029#include "Frame.h"
zalan@apple.come36543a2014-07-29 01:45:54 +000030#include "FrameSelection.h"
darin@apple.com15708b12014-03-16 16:38:58 +000031#include "HTMLElement.h"
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000032#include "HitTestLocation.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000033#include "InlineTextBox.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000034#include "LayoutRepainter.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000035#include "RenderCombineText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000036#include "RenderFlowThread.h"
zalan@apple.comac6956c2014-09-05 14:18:06 +000037#include "RenderInline.h"
akling@apple.comf3028052013-11-04 08:46:06 +000038#include "RenderIterator.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000039#include "RenderLayer.h"
zalan@apple.com8bf2a912015-04-10 03:15:50 +000040#include "RenderLineBreak.h"
antti@apple.com0b3dffe2014-03-24 16:30:52 +000041#include "RenderListItem.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000042#include "RenderMarquee.h"
hyatt@apple.comd4be3772014-01-24 19:55:33 +000043#include "RenderMultiColumnFlowThread.h"
44#include "RenderMultiColumnSet.h"
mihnea@adobe.combe79cf12013-10-17 09:02:19 +000045#include "RenderNamedFlowFragment.h"
hyatt@apple.com73715ca2014-05-06 21:35:52 +000046#include "RenderTableCell.h"
antti@apple.com940f5872013-10-24 20:31:11 +000047#include "RenderText.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000048#include "RenderView.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000049#include "Settings.h"
antti@apple.com940f5872013-10-24 20:31:11 +000050#include "SimpleLineLayoutFunctions.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000051#include "VerticalPositionCache.h"
weinig@apple.com611b9292013-10-20 22:57:54 +000052#include "VisiblePosition.h"
bfulgham@apple.comb5953432015-02-13 21:56:01 +000053#include <wtf/NeverDestroyed.h>
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000054
hyatt@apple.com5388e672013-09-06 20:54:47 +000055namespace WebCore {
56
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000057bool RenderBlock::s_canPropagateFloatIntoSibling = false;
58
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000059struct SameSizeAsMarginInfo {
60 uint32_t bitfields : 16;
61 LayoutUnit margins[2];
62};
63
64COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000065COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000066
67// Our MarginInfo state used when laying out block children.
hyatt@apple.com9a79c622015-09-15 18:38:18 +000068RenderBlockFlow::MarginInfo::MarginInfo(const RenderBlockFlow& block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000069 : m_atBeforeSideOfBlock(true)
70 , m_atAfterSideOfBlock(false)
71 , m_hasMarginBeforeQuirk(false)
72 , m_hasMarginAfterQuirk(false)
73 , m_determinedMarginBeforeQuirk(false)
74 , m_discardMargin(false)
75{
akling@apple.com827be9c2013-10-29 02:58:43 +000076 const RenderStyle& blockStyle = block.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +000077 ASSERT(block.isRenderView() || block.parent());
jfernandez@igalia.com136f1702014-12-08 19:13:16 +000078 m_canCollapseWithChildren = !block.createsNewFormattingContext() && !block.isRenderView();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000079
akling@apple.com827be9c2013-10-29 02:58:43 +000080 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle.marginBeforeCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000081
82 // If any height other than auto is specified in CSS, then we don't collapse our bottom
83 // margins with our children's margins. To do otherwise would be to risk odd visual
84 // effects when the children overflow out of the parent block and yet still collapse
85 // with it. We also don't collapse if we have any bottom border/padding.
86 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
akling@apple.com827be9c2013-10-29 02:58:43 +000087 && (blockStyle.logicalHeight().isAuto() && !blockStyle.logicalHeight().value()) && blockStyle.marginAfterCollapse() != MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000088
weinig@apple.com12840dc2013-10-22 23:59:08 +000089 m_quirkContainer = block.isTableCell() || block.isBody();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000090
weinig@apple.com12840dc2013-10-22 23:59:08 +000091 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block.mustDiscardMarginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000092
weinig@apple.com12840dc2013-10-22 23:59:08 +000093 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxPositiveMarginBefore() : LayoutUnit();
94 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block.mustDiscardMarginBefore()) ? block.maxNegativeMarginBefore() : LayoutUnit();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000095}
96
akling@apple.com689f7612014-12-14 08:21:05 +000097RenderBlockFlow::RenderBlockFlow(Element& element, Ref<RenderStyle>&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +000098 : RenderBlock(element, WTFMove(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +000099#if ENABLE(IOS_TEXT_AUTOSIZING)
100 , m_widthForTextAutosizing(-1)
101 , m_lineCountForTextAutosizing(NOT_SET)
102#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000103{
weinig@apple.com611b9292013-10-20 22:57:54 +0000104 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000105}
106
akling@apple.com689f7612014-12-14 08:21:05 +0000107RenderBlockFlow::RenderBlockFlow(Document& document, Ref<RenderStyle>&& style)
aestes@apple.com13aae082016-01-02 08:03:08 +0000108 : RenderBlock(document, WTFMove(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000109#if ENABLE(IOS_TEXT_AUTOSIZING)
110 , m_widthForTextAutosizing(-1)
111 , m_lineCountForTextAutosizing(NOT_SET)
112#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000113{
weinig@apple.com611b9292013-10-20 22:57:54 +0000114 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000115}
116
117RenderBlockFlow::~RenderBlockFlow()
118{
119}
120
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000121void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000122{
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000123 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
124 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000125 setChildrenInline(false); // Do this to avoid wrapping inline children that are just going to move into the flow thread.
abucur@adobe.com99757c62014-07-31 13:43:52 +0000126 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000127 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000128 flowThread->populate(); // Called after the flow thread is inserted so that we are reachable by the flow thread.
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000129 setMultiColumnFlowThread(flowThread);
130}
131
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000132void RenderBlockFlow::destroyMultiColumnFlowThread()
133{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000134 multiColumnFlowThread()->evacuateAndDestroy();
135 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000136}
137
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000138void RenderBlockFlow::insertedIntoTree()
139{
140 RenderBlock::insertedIntoTree();
141 createRenderNamedFlowFragmentIfNeeded();
142}
143
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000144void RenderBlockFlow::willBeDestroyed()
145{
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000146 if (renderNamedFlowFragment())
147 setRenderNamedFlowFragment(0);
weinig@apple.com611b9292013-10-20 22:57:54 +0000148
weinig@apple.com611b9292013-10-20 22:57:54 +0000149 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
150 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
151 destroyLeftoverChildren();
152
weinig@apple.com611b9292013-10-20 22:57:54 +0000153 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000154 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000155 // We can't wait for RenderBox::destroy to clear the selection,
156 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000157 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000158 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000159
160 // If we are an anonymous block, then our line boxes might have children
161 // that will outlast this block. In the non-anonymous block case those
162 // children will be destroyed by the time we return from this function.
163 if (isAnonymousBlock()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +0000164 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000165 while (auto childBox = box->firstChild())
166 childBox->removeFromParent();
167 }
168 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000169 } else if (parent())
170 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000171 }
172
akling@apple.com31dd4f42013-10-30 22:27:59 +0000173 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000174
dbates@webkit.org34f59002014-05-20 20:34:35 +0000175 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000176
177 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
178 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000179}
180
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000181RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
182{
183 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
184 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
185 // to avoid floats.
186 parentHasFloats = false;
187 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
188 if (is<RenderBlockFlow>(*sibling)) {
189 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
190 if (!siblingBlock.avoidsFloats())
191 return &siblingBlock;
192 }
193 if (sibling->isFloating())
194 parentHasFloats = true;
195 }
196 return nullptr;
197}
198
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000199void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000200{
201 if (m_floatingObjects)
202 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
203
204 HashSet<RenderBox*> oldIntrudingFloatSet;
205 if (!childrenInline() && m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000206 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
207 auto end = floatingObjectSet.end();
208 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
209 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000210 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000211 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000212 }
213 }
214
215 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000216 if (avoidsFloats() || isDocumentElementRenderer() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000217 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000218 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000219 if (!oldIntrudingFloatSet.isEmpty())
220 markAllDescendantsWithFloatsForLayout();
221 return;
222 }
223
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000224 RendererToFloatInfoMap floatMap;
225
226 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000227 if (childrenInline())
228 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
229 else
230 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000231 }
232
233 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
234 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
235 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000236 bool isBlockInsideInline = isAnonymousInlineBlock();
237 if (!is<RenderBlockFlow>(parent()) && !isBlockInsideInline)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000238 return;
239
robert@webkit.org97037ef2013-11-20 19:26:10 +0000240 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
241 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000242 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(isBlockInsideInline ? *containingBlock() : *parent());
243 bool parentHasFloats = isBlockInsideInline ? parentBlock.containsFloats() : false;
244 RenderBlockFlow* previousBlock = nullptr;
245 if (!isBlockInsideInline)
246 previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000247 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000248 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000249 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000250
251 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000252 if (previousBlock)
253 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000254 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000255 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000256 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000257 }
258
259 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000260 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000261 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000262
263 if (childrenInline()) {
264 LayoutUnit changeLogicalTop = LayoutUnit::max();
265 LayoutUnit changeLogicalBottom = LayoutUnit::min();
266 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000267 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
268 auto end = floatingObjectSet.end();
269 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000270 const auto& floatingObject = *it->get();
271 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject.renderer());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000272 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000273 if (oldFloatingObject) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000274 LayoutUnit oldLogicalBottom = logicalBottomForFloat(*oldFloatingObject);
275 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(*oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(*oldFloatingObject)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000276 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000277 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000278 } else {
279 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000280 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
281 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000282 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000283 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000284 LayoutUnit oldLogicalTop = logicalTopForFloat(*oldFloatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000285 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000286 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
287 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000288 }
289 }
290
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000291 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
292 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
293 oldFloatingObject->originatingLine()->markDirty();
294 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000295 } else {
296 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000297 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000298 }
299 }
300 }
301
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000302 auto end = floatMap.end();
303 for (auto it = floatMap.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +0000304 const auto& floatingObject = *it->value.get();
305 if (!floatingObject.isDescendant()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000306 changeLogicalTop = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000307 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000308 }
309 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000310
311 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
312 } else if (!oldIntrudingFloatSet.isEmpty()) {
313 // If there are previously intruding floats that no longer intrude, then children with floats
314 // should also get layout because they might need their floating object lists cleared.
315 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
316 markAllDescendantsWithFloatsForLayout();
317 else {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000318 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
319 auto end = floatingObjectSet.end();
320 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
321 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000322 if (!oldIntrudingFloatSet.isEmpty())
323 markAllDescendantsWithFloatsForLayout();
324 }
325 }
326}
327
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000328void RenderBlockFlow::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
329{
330 if (!style().hasAutoColumnCount() || !style().hasAutoColumnWidth()) {
331 // The min/max intrinsic widths calculated really tell how much space elements need when
332 // laid out inside the columns. In order to eventually end up with the desired column width,
333 // we need to convert them to values pertaining to the multicol container.
334 int columnCount = style().hasAutoColumnCount() ? 1 : style().columnCount();
335 LayoutUnit columnWidth;
336 LayoutUnit colGap = columnGap();
337 LayoutUnit gapExtra = (columnCount - 1) * colGap;
338 if (style().hasAutoColumnWidth())
339 minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
340 else {
341 columnWidth = style().columnWidth();
342 minLogicalWidth = std::min(minLogicalWidth, columnWidth);
343 }
344 // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
345 // intrinsic width, instead of pretending that it's 1. The only way to do that is by
346 // performing a layout pass, but this is not an appropriate time or place for layout. The
347 // good news is that if height is unconstrained and there are no explicit breaks, the
348 // resolved column-count really should be 1.
349 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
350 }
351}
352
353void RenderBlockFlow::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
354{
zalan@apple.comac6956c2014-09-05 14:18:06 +0000355 if (childrenInline())
356 computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
357 else
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000358 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
359
360 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
361
362 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
363
364 if (!style().autoWrap() && childrenInline()) {
365 // A horizontal marquee with inline children has no minimum width.
366 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
367 minLogicalWidth = 0;
368 }
369
cdumez@apple.com8faf7722014-10-13 18:21:11 +0000370 if (is<RenderTableCell>(*this)) {
371 Length tableCellWidth = downcast<RenderTableCell>(*this).styleOrColLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000372 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
373 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
374 }
375
rego@igalia.com76760c72015-05-14 16:37:27 +0000376 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000377 maxLogicalWidth += scrollbarWidth;
378 minLogicalWidth += scrollbarWidth;
379}
380
381bool RenderBlockFlow::recomputeLogicalWidthAndColumnWidth()
382{
383 bool changed = recomputeLogicalWidth();
384
385 LayoutUnit oldColumnWidth = computedColumnWidth();
386 computeColumnCountAndWidth();
387
388 return changed || oldColumnWidth != computedColumnWidth();
389}
390
391LayoutUnit RenderBlockFlow::columnGap() const
392{
393 if (style().hasNormalColumnGap())
394 return style().fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
395 return style().columnGap();
396}
397
398void RenderBlockFlow::computeColumnCountAndWidth()
399{
400 // Calculate our column width and column count.
401 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
402 unsigned desiredColumnCount = 1;
403 LayoutUnit desiredColumnWidth = contentLogicalWidth();
404
405 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
406 if (document().paginated() || (style().hasAutoColumnCount() && style().hasAutoColumnWidth()) || !style().hasInlineColumnAxis()) {
407 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
408 return;
409 }
410
411 LayoutUnit availWidth = desiredColumnWidth;
412 LayoutUnit colGap = columnGap();
413 LayoutUnit colWidth = std::max<LayoutUnit>(LayoutUnit::fromPixel(1), LayoutUnit(style().columnWidth()));
414 int colCount = std::max<int>(1, style().columnCount());
415
416 if (style().hasAutoColumnWidth() && !style().hasAutoColumnCount()) {
417 desiredColumnCount = colCount;
418 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
419 } else if (!style().hasAutoColumnWidth() && style().hasAutoColumnCount()) {
420 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
421 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
422 } else {
423 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
424 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
425 }
426 setComputedColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
427}
428
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000429void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
430{
431 ASSERT(needsLayout());
432
433 if (!relayoutChildren && simplifiedLayout())
434 return;
435
436 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
437
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000438 if (recomputeLogicalWidthAndColumnWidth())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000439 relayoutChildren = true;
440
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000441 rebuildFloatingObjectSetFromIntrudingFloats();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000442
443 LayoutUnit previousHeight = logicalHeight();
444 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
445 // for consistency with other render classes?
446 setLogicalHeight(0);
447
448 bool pageLogicalHeightChanged = false;
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000449 checkForPaginationLogicalHeightChange(relayoutChildren, pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000450
akling@apple.com827be9c2013-10-29 02:58:43 +0000451 const RenderStyle& styleToUse = style();
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000452 LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || styleToUse.isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000453
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000454 preparePaginationBeforeBlockLayout(relayoutChildren);
abucur@adobe.com0e81bc72013-10-22 14:50:37 +0000455 if (!relayoutChildren)
456 relayoutChildren = namedFlowFragmentNeedsUpdate();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000457
458 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
459 // our current maximal positive and negative margins. These values are used when we
460 // are collapsed with adjacent blocks, so for example, if you have block A and B
461 // collapsing together, then you'd take the maximal positive margin from both A and B
462 // and subtract it from the maximal negative margin from both A and B to get the
463 // true collapsed margin. This algorithm is recursive, so when we finish layout()
464 // our block knows its current maximal positive/negative values.
465 //
466 // Start out by setting our margin values to our current margins. Table cells have
467 // no margins, so we don't fill in the values for table cells.
468 bool isCell = isTableCell();
469 if (!isCell) {
470 initMaxMarginValues();
471
akling@apple.com827be9c2013-10-29 02:58:43 +0000472 setHasMarginBeforeQuirk(styleToUse.hasMarginBeforeQuirk());
473 setHasMarginAfterQuirk(styleToUse.hasMarginAfterQuirk());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000474 setPaginationStrut(0);
475 }
476
477 LayoutUnit repaintLogicalTop = 0;
478 LayoutUnit repaintLogicalBottom = 0;
479 LayoutUnit maxFloatLogicalBottom = 0;
480 if (!firstChild() && !isAnonymousBlock())
481 setChildrenInline(true);
482 if (childrenInline())
483 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
484 else
485 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
486
487 // Expand our intrinsic height to encompass floats.
488 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
jfernandez@igalia.com136f1702014-12-08 19:13:16 +0000489 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && createsNewFormattingContext())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000490 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
491
hyatt@apple.com73715ca2014-05-06 21:35:52 +0000492 if (relayoutForPagination(statePusher) || relayoutToAvoidWidows(statePusher)) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000493 ASSERT(!shouldBreakAtLineToAvoidWidow());
494 return;
495 }
496
497 // Calculate our new height.
498 LayoutUnit oldHeight = logicalHeight();
499 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
500
501 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
502 // This ensures the size information is correctly computed for the last auto-height region receiving content.
cdumez@apple.com3abcc792014-10-20 03:42:03 +0000503 if (is<RenderFlowThread>(*this))
504 downcast<RenderFlowThread>(*this).applyBreakAfterContent(oldClientAfterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000505
506 updateLogicalHeight();
507 LayoutUnit newHeight = logicalHeight();
508 if (oldHeight != newHeight) {
509 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
510 // One of our children's floats may have become an overhanging float for us. We need to look for it.
akling@apple.com525dae62014-01-03 20:22:09 +0000511 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
512 if (blockFlow.isFloatingOrOutOfFlowPositioned())
513 continue;
514 if (blockFlow.lowestFloatLogicalBottom() + blockFlow.logicalTop() > newHeight)
515 addOverhangingFloats(blockFlow, false);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000516 }
517 }
518 }
519
520 bool heightChanged = (previousHeight != newHeight);
521 if (heightChanged)
522 relayoutChildren = true;
523
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +0000524 layoutPositionedObjects(relayoutChildren || isDocumentElementRenderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000525
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000526 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
527 computeOverflow(oldClientAfterEdge);
528
529 statePusher.pop();
530
531 fitBorderToLinesIfNeeded();
532
533 if (view().layoutState()->m_pageLogicalHeight)
534 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
535
536 updateLayerTransform();
537
538 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
539 // we overflow or not.
540 updateScrollInfoAfterLayout();
541
542 // FIXME: This repaint logic should be moved into a separate helper function!
543 // Repaint with our new bounds if they are different from our old bounds.
544 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000545 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000546 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
547 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
548 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
549 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
550 if (hasOverflowClip()) {
551 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
552 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
553 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000554 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
555 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000556 }
557
558 LayoutRect repaintRect;
559 if (isHorizontalWritingMode())
560 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
561 else
562 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
563
zalan@apple.com825fc9a2015-08-21 02:57:32 +0000564 repaintRect.inflate(view().maximalOutlineSize());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000565
566 if (hasOverflowClip()) {
567 // Adjust repaint rect for scroll offset
568 repaintRect.move(-scrolledContentOffset());
569
570 // Don't allow this rect to spill out of our overflow box.
571 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
572 }
573
574 // Make sure the rect is still non-empty after intersecting for overflow above
575 if (!repaintRect.isEmpty()) {
576 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
577 if (hasReflection())
578 repaintRectangle(reflectedRect(repaintRect));
579 }
580 }
581
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000582 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000583}
584
585void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
586{
587 dirtyForLayoutFromPercentageHeightDescendants();
588
589 LayoutUnit beforeEdge = borderAndPaddingBefore();
590 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
591
592 setLogicalHeight(beforeEdge);
593
594 // Lay out our hypothetical grid line as though it occurs at the top of the block.
595 if (view().layoutState()->lineGrid() == this)
596 layoutLineGridBox();
597
598 // The margin struct caches all our current margin collapsing state.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000599 MarginInfo marginInfo(*this, beforeEdge, afterEdge);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000600
601 // Fieldsets need to find their legend and position it inside the border of the object.
602 // The legend then gets skipped during normal layout. The same is true for ruby text.
603 // It doesn't get included in the normal layout process but is instead skipped.
604 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
605
606 LayoutUnit previousFloatLogicalBottom = 0;
607 maxFloatLogicalBottom = 0;
608
609 RenderBox* next = firstChildBox();
610
611 while (next) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000612 RenderBox& child = *next;
613 next = child.nextSiblingBox();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000614
weinig@apple.com12840dc2013-10-22 23:59:08 +0000615 if (childToExclude == &child)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000616 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
617
618 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
619
weinig@apple.com12840dc2013-10-22 23:59:08 +0000620 if (child.isOutOfFlowPositioned()) {
621 child.containingBlock()->insertPositionedObject(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000622 adjustPositionedBlock(child, marginInfo);
623 continue;
624 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000625 if (child.isFloating()) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000626 insertFloatingObject(child);
627 adjustFloatingBlock(marginInfo);
628 continue;
629 }
630
631 // Lay out the child.
632 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
633 }
634
635 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
636 // determining the correct collapsed bottom margin information.
637 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
638}
639
antti@apple.com940f5872013-10-24 20:31:11 +0000640void RenderBlockFlow::layoutInlineChildren(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
641{
akling@apple.coma12fee22015-02-01 02:58:13 +0000642 if (lineLayoutPath() == UndeterminedPath)
643 setLineLayoutPath(SimpleLineLayout::canUseFor(*this) ? SimpleLinesPath : LineBoxesPath);
antti@apple.com42fb53d2013-10-25 02:33:11 +0000644
akling@apple.coma12fee22015-02-01 02:58:13 +0000645 if (lineLayoutPath() == SimpleLinesPath) {
zalan@apple.come37da962014-12-11 03:29:29 +0000646 layoutSimpleLines(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
antti@apple.com940f5872013-10-24 20:31:11 +0000647 return;
648 }
649
antti@apple.comfea51992013-10-28 13:39:23 +0000650 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +0000651 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
652}
653
weinig@apple.com12840dc2013-10-22 23:59:08 +0000654void RenderBlockFlow::layoutBlockChild(RenderBox& child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000655{
656 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
657 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
658
659 // The child is a normal flow object. Compute the margins we will use for collapsing now.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000660 child.computeAndSetBlockDirectionMargins(this);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000661
662 // Try to guess our correct logical top position. In most cases this guess will
663 // be correct. Only if we're wrong (when we compute the real logical top position)
664 // will we have to potentially relayout.
665 LayoutUnit estimateWithoutPagination;
666 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
667
668 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000669 LayoutRect oldRect = child.frameRect();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000670 LayoutUnit oldLogicalTop = logicalTopForChild(child);
671
672#if !ASSERT_DISABLED
673 LayoutSize oldLayoutDelta = view().layoutDelta();
674#endif
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000675 // Position the child as though it didn't collapse with the top.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000676 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
677 estimateRegionRangeForBoxChild(child);
678
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000679 RenderBlockFlow* childBlockFlow = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000680 bool markDescendantsWithFloats = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000681 if (logicalTopEstimate != oldLogicalTop && !child.avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000682 markDescendantsWithFloats = true;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000683 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
684 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
685 // very large elements. If it does the comparison with oldLogicalTop might yield a
686 // false negative as adding and removing margins, borders etc from a saturated number
687 // might yield incorrect results. If this is the case always mark for layout.
688 markDescendantsWithFloats = true;
weinig@apple.com12840dc2013-10-22 23:59:08 +0000689 else if (!child.avoidsFloats() || child.shrinkToAvoidFloats()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000690 // If an element might be affected by the presence of floats, then always mark it for
691 // layout.
andersca@apple.com86298632013-11-10 19:32:33 +0000692 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000693 if (fb > logicalTopEstimate)
694 markDescendantsWithFloats = true;
695 }
696
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000697 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000698 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000699 childBlockFlow->markAllDescendantsWithFloatsForLayout();
weinig@apple.com12840dc2013-10-22 23:59:08 +0000700 if (!child.isWritingModeRoot())
andersca@apple.com86298632013-11-10 19:32:33 +0000701 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000702 }
703
hyatt@apple.comccad3742015-02-04 21:39:00 +0000704 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000705
weinig@apple.com12840dc2013-10-22 23:59:08 +0000706 bool childHadLayout = child.everHadLayout();
707 bool childNeededLayout = child.needsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000708 if (childNeededLayout)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000709 child.layout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000710
711 // Cache if we are at the top of the block right now.
712 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
713
714 // Now determine the correct ypos based off examination of collapsing margin
715 // values.
716 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
717
718 // Now check for clear.
719 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
720
721 bool paginated = view().layoutState()->isPaginated();
722 if (paginated)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000723 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000724
725 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
726
727 // Now we have a final top position. See if it really does end up being different from our estimate.
728 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
729 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000730 if (logicalTopAfterClear != logicalTopEstimate || child.needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
731 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +0000732 // The child's width depends on the line width. When the child shifts to clear an item, its width can
733 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000734 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000735 }
736
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000737 if (childBlockFlow) {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000738 if (!child.avoidsFloats() && childBlockFlow->containsFloats())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000739 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +0000740 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000741 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000742 }
743
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000744 if (updateRegionRangeForBoxChild(child))
weinig@apple.com12840dc2013-10-22 23:59:08 +0000745 child.setNeedsLayout(MarkOnlyThis);
abucur@adobe.comeaf5e222014-05-14 14:35:07 +0000746
747 // In case our guess was wrong, relayout the child.
748 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000749
750 // We are no longer at the top of the block if we encounter a non-empty child.
751 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000752 if (marginInfo.atBeforeSideOfBlock() && !child.isSelfCollapsingBlock())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000753 marginInfo.setAtBeforeSideOfBlock(false);
754
755 // Now place the child in the correct left position
756 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
757
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000758 // Update our height now that the child has been placed in the correct position.
stavila@adobe.comb0d86c42014-04-09 17:07:50 +0000759 setLogicalHeight(logicalHeight() + logicalHeightForChildForFragmentation(child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000760 if (mustSeparateMarginAfterForChild(child)) {
761 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
762 marginInfo.clearMargin();
763 }
764 // If the child has overhanging floats that intrude into following siblings (or possibly out
765 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000766 if (childBlockFlow && childBlockFlow->containsFloats())
andersca@apple.com86298632013-11-10 19:32:33 +0000767 maxFloatLogicalBottom = std::max(maxFloatLogicalBottom, addOverhangingFloats(*childBlockFlow, !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000768
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +0000769 LayoutSize childOffset = child.location() - oldRect.location();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000770 if (childOffset.width() || childOffset.height()) {
771 view().addLayoutDelta(childOffset);
772
773 // If the child moved, we have to repaint it as well as any floating/positioned
774 // descendants. An exception is if we need a layout. In this case, we know we're going to
775 // repaint ourselves (and the child) anyway.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000776 if (childHadLayout && !selfNeedsLayout() && child.checkForRepaintDuringLayout())
777 child.repaintDuringLayoutIfMoved(oldRect);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000778 }
779
weinig@apple.com12840dc2013-10-22 23:59:08 +0000780 if (!childHadLayout && child.checkForRepaintDuringLayout()) {
781 child.repaint();
782 child.repaintOverhangingFloats(true);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000783 }
784
785 if (paginated) {
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000786 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
787 flowThread->flowThreadDescendantBoxLaidOut(&child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000788 // Check for an after page/column break.
789 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
790 if (newHeight != height())
791 setLogicalHeight(newHeight);
792 }
793
794 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
795}
796
weinig@apple.com12840dc2013-10-22 23:59:08 +0000797void RenderBlockFlow::adjustPositionedBlock(RenderBox& child, const MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000798{
799 bool isHorizontal = isHorizontalWritingMode();
akling@apple.com827be9c2013-10-29 02:58:43 +0000800 bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontal);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000801
802 LayoutUnit logicalTop = logicalHeight();
803 updateStaticInlinePositionForChild(child, logicalTop);
804
805 if (!marginInfo.canCollapseWithMarginBefore()) {
806 // Positioned blocks don't collapse margins, so add the margin provided by
807 // the container now. The child's own margin is added later when calculating its logical top.
808 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
809 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
810 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
811 }
812
weinig@apple.com12840dc2013-10-22 23:59:08 +0000813 RenderLayer* childLayer = child.layer();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000814 if (childLayer->staticBlockPosition() != logicalTop) {
815 childLayer->setStaticBlockPosition(logicalTop);
816 if (hasStaticBlockPosition)
weinig@apple.com12840dc2013-10-22 23:59:08 +0000817 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000818 }
819}
820
robert@webkit.org97037ef2013-11-20 19:26:10 +0000821LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock()
822{
823 ASSERT(isSelfCollapsingBlock());
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000824 RenderBlockFlow* parentBlock = downcast<RenderBlockFlow>(parent());
robert@webkit.org97037ef2013-11-20 19:26:10 +0000825 if (parentBlock && style().clear() && parentBlock->getClearDelta(*this, logicalHeight()))
826 return marginValuesForChild(*this).positiveMarginBefore();
827 return LayoutUnit();
828}
829
hyatt@apple.com31a5daa2014-01-28 01:26:37 +0000830void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox& child, ApplyLayoutDeltaMode applyDelta)
831{
832 LayoutUnit startPosition = borderStart() + paddingStart();
833 if (style().shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
834 startPosition -= verticalScrollbarWidth();
835 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
836
837 // Add in our start margin.
838 LayoutUnit childMarginStart = marginStartForChild(child);
839 LayoutUnit newPosition = startPosition + childMarginStart;
840
841 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
842 // to shift over as necessary to dodge any floats that might get in the way.
843 if (child.avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
844 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
845
846 setLogicalLeftForChild(child, style().isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
847}
robert@webkit.org97037ef2013-11-20 19:26:10 +0000848
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000849void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
850{
851 // The float should be positioned taking into account the bottom margin
852 // of the previous flow. We add that margin into the height, get the
853 // float positioned properly, and then subtract the margin out of the
854 // height again. In the case of self-collapsing blocks, we always just
855 // use the top margins, since the self-collapsing block collapsed its
856 // own bottom margin into its top margin.
857 //
858 // Note also that the previous flow may collapse its margin into the top of
859 // our block. If this is the case, then we do not add the margin in to our
860 // height when computing the position of the float. This condition can be tested
861 // for by simply calling canCollapseWithMarginBefore. See
862 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
863 // an example of this scenario.
864 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
865 setLogicalHeight(logicalHeight() + marginOffset);
866 positionNewFloats();
867 setLogicalHeight(logicalHeight() - marginOffset);
868}
869
weinig@apple.com12840dc2013-10-22 23:59:08 +0000870void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox& child, LayoutUnit logicalTop)
871{
akling@apple.com827be9c2013-10-29 02:58:43 +0000872 if (child.style().isOriginalDisplayInlineType())
weinig@apple.com12840dc2013-10-22 23:59:08 +0000873 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false));
874 else
875 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
876}
877
878void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox& child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
879{
880 if (flowThreadContainingBlock()) {
881 // Shift the inline position to exclude the region offset.
882 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
883 }
884 child.layer()->setStaticInlinePosition(inlinePosition);
885}
886
887RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000888{
889 LayoutUnit childBeforePositive = 0;
890 LayoutUnit childBeforeNegative = 0;
891 LayoutUnit childAfterPositive = 0;
892 LayoutUnit childAfterNegative = 0;
893
894 LayoutUnit beforeMargin = 0;
895 LayoutUnit afterMargin = 0;
896
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000897 RenderBlockFlow* childRenderBlock = is<RenderBlockFlow>(child) ? &downcast<RenderBlockFlow>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000898
899 // If the child has the same directionality as we do, then we can just return its
900 // margins in the same direction.
weinig@apple.com12840dc2013-10-22 23:59:08 +0000901 if (!child.isWritingModeRoot()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000902 if (childRenderBlock) {
903 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
904 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
905 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
906 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
907 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000908 beforeMargin = child.marginBefore();
909 afterMargin = child.marginAfter();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000910 }
weinig@apple.com12840dc2013-10-22 23:59:08 +0000911 } else if (child.isHorizontalWritingMode() == isHorizontalWritingMode()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000912 // The child has a different directionality. If the child is parallel, then it's just
913 // flipped relative to us. We can use the margins for the opposite edges.
914 if (childRenderBlock) {
915 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
916 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
917 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
918 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
919 } else {
weinig@apple.com12840dc2013-10-22 23:59:08 +0000920 beforeMargin = child.marginAfter();
921 afterMargin = child.marginBefore();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000922 }
923 } else {
924 // The child is perpendicular to us, which means its margins don't collapse but are on the
925 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
926 beforeMargin = marginBeforeForChild(child);
927 afterMargin = marginAfterForChild(child);
928 }
929
930 // Resolve uncollapsing margins into their positive/negative buckets.
931 if (beforeMargin) {
932 if (beforeMargin > 0)
933 childBeforePositive = beforeMargin;
934 else
935 childBeforeNegative = -beforeMargin;
936 }
937 if (afterMargin) {
938 if (afterMargin > 0)
939 childAfterPositive = afterMargin;
940 else
941 childAfterNegative = -afterMargin;
942 }
943
944 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
945}
946
hyatt@apple.com72311dc2015-09-10 22:15:46 +0000947bool RenderBlockFlow::childrenPreventSelfCollapsing() const
948{
949 if (!childrenInline())
950 return RenderBlock::childrenPreventSelfCollapsing();
951
952 // If the block has inline children, see if we generated any line boxes. If we have any
953 // line boxes, then we can only be self-collapsing if we have nothing but anonymous inline blocks
954 // that are also self-collapsing inside us.
955 if (!hasLines())
956 return false;
957
958 if (simpleLineLayout())
959 return true; // We have simple line layout lines, so we can't be self-collapsing.
960
961 for (auto* child = firstRootBox(); child; child = child->nextRootBox()) {
962 if (!child->hasAnonymousInlineBlock() || !child->anonymousInlineBlock()->isSelfCollapsingBlock())
963 return true;
964 }
965 return false; // We have no line boxes, so we must be self-collapsing.
966}
967
weinig@apple.com12840dc2013-10-22 23:59:08 +0000968LayoutUnit RenderBlockFlow::collapseMargins(RenderBox& child, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000969{
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000970 return collapseMarginsWithChildInfo(&child, child.previousSibling(), marginInfo);
971}
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000972
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000973LayoutUnit RenderBlockFlow::collapseMarginsWithChildInfo(RenderBox* child, RenderObject* prevSibling, MarginInfo& marginInfo)
974{
975 bool childDiscardMarginBefore = child ? mustDiscardMarginBeforeForChild(*child) : false;
976 bool childDiscardMarginAfter = child ? mustDiscardMarginAfterForChild(*child) : false;
977 bool childIsSelfCollapsing = child ? child->isSelfCollapsingBlock() : false;
978 bool beforeQuirk = child ? hasMarginBeforeQuirk(*child) : false;
979 bool afterQuirk = child ? hasMarginAfterQuirk(*child) : false;
980
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000981 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
982 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000983
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000984 // Get the four margin values for the child and cache them.
hyatt@apple.com9a79c622015-09-15 18:38:18 +0000985 const MarginValues childMargins = child ? marginValuesForChild(*child) : MarginValues(0, 0, 0, 0);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000986
987 // Get our max pos and neg top margins.
988 LayoutUnit posTop = childMargins.positiveMarginBefore();
989 LayoutUnit negTop = childMargins.negativeMarginBefore();
990
991 // For self-collapsing blocks, collapse our bottom margins into our
992 // top to get new posTop and negTop values.
993 if (childIsSelfCollapsing) {
andersca@apple.com86298632013-11-10 19:32:33 +0000994 posTop = std::max(posTop, childMargins.positiveMarginAfter());
995 negTop = std::max(negTop, childMargins.negativeMarginAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000996 }
997
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000998 if (marginInfo.canCollapseWithMarginBefore()) {
999 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1000 // This child is collapsing with the top of the
1001 // block. If it has larger margin values, then we need to update
1002 // our own maximal values.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001003 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !beforeQuirk)
andersca@apple.com86298632013-11-10 19:32:33 +00001004 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001005
1006 // The minute any of the margins involved isn't a quirk, don't
1007 // collapse it away, even if the margin is smaller (www.webreference.com
1008 // has an example of this, a <dt> with 0.8em author-specified inside
1009 // a <dl> inside a <td>.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001010 if (!marginInfo.determinedMarginBeforeQuirk() && !beforeQuirk && (posTop - negTop)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001011 setHasMarginBeforeQuirk(false);
1012 marginInfo.setDeterminedMarginBeforeQuirk(true);
1013 }
1014
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001015 if (!marginInfo.determinedMarginBeforeQuirk() && beforeQuirk && !marginBefore()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001016 // We have no top margin and our top child has a quirky margin.
1017 // We will pick up this quirky margin and pass it through.
1018 // This deals with the <td><div><p> case.
1019 // Don't do this for a block that split two inlines though. You do
1020 // still apply margins in this case.
1021 setHasMarginBeforeQuirk(true);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001022 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001023 } else
1024 // The before margin of the container will also discard all the margins it is collapsing with.
1025 setMustDiscardMarginBefore();
1026 }
1027
1028 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
1029 if (childDiscardMarginBefore) {
1030 marginInfo.setDiscardMargin(true);
1031 marginInfo.clearMargin();
1032 }
1033
1034 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001035 marginInfo.setHasMarginBeforeQuirk(beforeQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001036
1037 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
1038 LayoutUnit logicalTop = beforeCollapseLogicalTop;
robert@webkit.org97037ef2013-11-20 19:26:10 +00001039
1040 LayoutUnit clearanceForSelfCollapsingBlock;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001041
robert@webkit.org97037ef2013-11-20 19:26:10 +00001042 // 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
1043 // 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
1044 // margin top of the self-collapsing block. If the resulting collapsed margin leaves the child still intruding into the float then we will want to clear it.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001045 if (!marginInfo.canCollapseWithMarginBefore() && is<RenderBlockFlow>(prevSibling) && downcast<RenderBlockFlow>(*prevSibling).isSelfCollapsingBlock()) {
1046 clearanceForSelfCollapsingBlock = downcast<RenderBlockFlow>(*prevSibling).marginOffsetForSelfCollapsingBlock();
robert@webkit.org97037ef2013-11-20 19:26:10 +00001047 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock);
1048 }
1049
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001050 if (childIsSelfCollapsing) {
1051 // 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.
1052 // Also, the child's top position equals the logical height of the container.
1053 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
1054 // This child has no height. We need to compute our
1055 // position before we collapse the child's margins together,
1056 // so that we can get an accurate position for the zero-height block.
andersca@apple.com86298632013-11-10 19:32:33 +00001057 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1058 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001059 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1060
1061 // Now collapse the child's margins together, which means examining our
1062 // bottom margin values as well.
1063 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1064 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1065
1066 if (!marginInfo.canCollapseWithMarginBefore())
1067 // We need to make sure that the position of the self-collapsing block
1068 // is correct, since it could have overflowing content
1069 // that needs to be positioned correctly (e.g., a block that
1070 // had a specified height of 0 but that actually had subcontent).
1071 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1072 }
1073 } else {
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001074 if (child && mustSeparateMarginBeforeForChild(*child)) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001075 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
1076 // If we are at the before side of the block and we collapse, ignore the computed margin
1077 // and just add the child margin to the container height. This will correctly position
1078 // the child inside the container.
zalan@apple.coma4d00552014-01-25 00:21:59 +00001079 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit::fromPixel(0);
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001080 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(*child));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001081 logicalTop = logicalHeight();
1082 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
1083 || (!marginInfo.canCollapseMarginBeforeWithChildren()
1084 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
1085 // We're collapsing with a previous sibling's margins and not
1086 // with the top of the block.
andersca@apple.com86298632013-11-10 19:32:33 +00001087 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001088 logicalTop = logicalHeight();
1089 }
1090
1091 marginInfo.setDiscardMargin(childDiscardMarginAfter);
1092
1093 if (!marginInfo.discardMargin()) {
1094 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1095 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1096 } else
1097 marginInfo.clearMargin();
1098
1099 if (marginInfo.margin())
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001100 marginInfo.setHasMarginAfterQuirk(afterQuirk);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001101 }
1102
1103 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1104 // collapsed into the page edge.
1105 LayoutState* layoutState = view().layoutState();
1106 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
1107 && hasNextPage(beforeCollapseLogicalTop)) {
1108 LayoutUnit oldLogicalTop = logicalTop;
andersca@apple.com86298632013-11-10 19:32:33 +00001109 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001110 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1111 }
1112
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001113 if (is<RenderBlockFlow>(prevSibling) && !prevSibling->isFloatingOrOutOfFlowPositioned()) {
robert@webkit.org97037ef2013-11-20 19:26:10 +00001114 // 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
1115 // any floats from the parent will now overhang.
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001116 RenderBlockFlow& block = downcast<RenderBlockFlow>(*prevSibling);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001117 LayoutUnit oldLogicalHeight = logicalHeight();
1118 setLogicalHeight(logicalTop);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001119 if (block.containsFloats() && !block.avoidsFloats() && (block.logicalTop() + block.lowestFloatLogicalBottom()) > logicalTop)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001120 addOverhangingFloats(block, false);
robert@webkit.org97037ef2013-11-20 19:26:10 +00001121 setLogicalHeight(oldLogicalHeight);
1122
1123 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up
1124 // 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
1125 // floats in the parent that overhang |child|'s new logical top.
1126 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop;
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001127 if (child && logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1128 child->setNeedsLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001129 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001130
1131 return logicalTop;
1132}
1133
weinig@apple.com12840dc2013-10-22 23:59:08 +00001134LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox& child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001135{
1136 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1137 if (!heightIncrease)
1138 return yPos;
1139
weinig@apple.com12840dc2013-10-22 23:59:08 +00001140 if (child.isSelfCollapsingBlock()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001141 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1142
1143 // For self-collapsing blocks that clear, they can still collapse their
1144 // margins with following siblings. Reset the current margins to represent
1145 // the self-collapsing block's margins only.
1146 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
robert@webkit.org97037ef2013-11-20 19:26:10 +00001147 MarginValues childMargins = marginValuesForChild(child);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001148 if (!childDiscardMargin) {
andersca@apple.com86298632013-11-10 19:32:33 +00001149 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1150 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001151 } else
1152 marginInfo.clearMargin();
1153 marginInfo.setDiscardMargin(childDiscardMargin);
1154
1155 // CSS2.1 states:
1156 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1157 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1158 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1159 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1160 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001161 for (RenderBox* curr = child.nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001162 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1163 wouldCollapseMarginsWithParent = false;
1164 }
1165 if (wouldCollapseMarginsWithParent)
1166 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1167
robert@webkit.org97037ef2013-11-20 19:26:10 +00001168 // 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
1169 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will
1170 // 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
1171 // margins can collapse at the correct vertical position.
1172 // 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
1173 // (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],
1174 // i.e., clearance = [height of float] - margin-top".
1175 setLogicalHeight(child.logicalTop() + childMargins.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001176 } else
1177 // Increase our height by the amount we had to clear.
1178 setLogicalHeight(logicalHeight() + heightIncrease);
1179
1180 if (marginInfo.canCollapseWithMarginBefore()) {
1181 // We can no longer collapse with the top of the block since a clear
1182 // occurred. The empty blocks collapse into the cleared block.
1183 // FIXME: This isn't quite correct. Need clarification for what to do
1184 // if the height the cleared block is offset by is smaller than the
1185 // margins involved.
1186 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1187 marginInfo.setAtBeforeSideOfBlock(false);
1188
1189 // 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 +00001190 setMustDiscardMarginBefore(style().marginBeforeCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001191 }
1192
robert@webkit.org97037ef2013-11-20 19:26:10 +00001193 return yPos + heightIncrease;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001194}
1195
weinig@apple.com12840dc2013-10-22 23:59:08 +00001196void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox& child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001197{
1198 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1199 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1200 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001201 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child.style().marginBeforeCollapse() == MSEPARATE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001202 return;
1203
1204 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1205 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
akling@apple.com827be9c2013-10-29 02:58:43 +00001206 if (child.style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001207 positiveMarginBefore = 0;
1208 negativeMarginBefore = 0;
1209 discardMarginBefore = true;
1210 return;
1211 }
1212
1213 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001214 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin);
1215 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001216
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001217 if (!is<RenderBlockFlow>(child))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001218 return;
1219
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001220 RenderBlockFlow& childBlock = downcast<RenderBlockFlow>(child);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001221 if (childBlock.childrenInline() || childBlock.isWritingModeRoot())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001222 return;
1223
weinig@apple.com12840dc2013-10-22 23:59:08 +00001224 MarginInfo childMarginInfo(childBlock, childBlock.borderAndPaddingBefore(), childBlock.borderAndPaddingAfter());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001225 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1226 return;
1227
weinig@apple.com12840dc2013-10-22 23:59:08 +00001228 RenderBox* grandchildBox = childBlock.firstChildBox();
1229 for (; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001230 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1231 break;
1232 }
1233
1234 // 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 +00001235 if (!grandchildBox || grandchildBox->style().clear() != CNONE)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001236 return;
1237
1238 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1239 if (grandchildBox->needsLayout()) {
1240 grandchildBox->computeAndSetBlockDirectionMargins(this);
cdumez@apple.come9437792014-10-08 23:33:43 +00001241 if (is<RenderBlock>(*grandchildBox)) {
1242 RenderBlock& grandchildBlock = downcast<RenderBlock>(*grandchildBox);
1243 grandchildBlock.setHasMarginBeforeQuirk(grandchildBox->style().hasMarginBeforeQuirk());
1244 grandchildBlock.setHasMarginAfterQuirk(grandchildBox->style().hasMarginAfterQuirk());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001245 }
1246 }
1247
1248 // Collapse the margin of the grandchild box with our own to produce an estimate.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001249 childBlock.marginBeforeEstimateForChild(*grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001250}
1251
weinig@apple.com12840dc2013-10-22 23:59:08 +00001252LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox& child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001253{
1254 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1255 // relayout if there are intruding floats.
1256 LayoutUnit logicalTopEstimate = logicalHeight();
1257 if (!marginInfo.canCollapseWithMarginBefore()) {
1258 LayoutUnit positiveMarginBefore = 0;
1259 LayoutUnit negativeMarginBefore = 0;
1260 bool discardMarginBefore = false;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001261 if (child.selfNeedsLayout()) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001262 // Try to do a basic estimation of how the collapse is going to go.
1263 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1264 } else {
1265 // Use the cached collapsed margin values from a previous layout. Most of the time they
1266 // will be right.
1267 MarginValues marginValues = marginValuesForChild(child);
andersca@apple.com86298632013-11-10 19:32:33 +00001268 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore());
1269 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001270 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1271 }
1272
1273 // Collapse the result with our current margins.
1274 if (!discardMarginBefore)
andersca@apple.com86298632013-11-10 19:32:33 +00001275 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001276 }
1277
1278 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1279 // page.
1280 LayoutState* layoutState = view().layoutState();
1281 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1282 && hasNextPage(logicalHeight()))
andersca@apple.com86298632013-11-10 19:32:33 +00001283 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001284
1285 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1286
1287 estimateWithoutPagination = logicalTopEstimate;
1288
1289 if (layoutState->isPaginated()) {
1290 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1291 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1292
1293 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1294 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1295
cdumez@apple.come9437792014-10-08 23:33:43 +00001296 if (!child.selfNeedsLayout() && is<RenderBlock>(child))
1297 logicalTopEstimate += downcast<RenderBlock>(child).paginationStrut();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001298 }
1299
1300 return logicalTopEstimate;
1301}
1302
1303void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1304{
1305 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1306 // 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.
1307 // Don't update the max margin values because we won't need them anyway.
1308 if (marginInfo.discardMargin()) {
1309 setMustDiscardMarginAfter();
1310 return;
1311 }
1312
1313 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1314 // with our children.
andersca@apple.com86298632013-11-10 19:32:33 +00001315 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001316
1317 if (!marginInfo.hasMarginAfterQuirk())
1318 setHasMarginAfterQuirk(false);
1319
1320 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1321 // We have no bottom margin and our last child has a quirky margin.
1322 // We will pick up this quirky margin and pass it through.
1323 // This deals with the <td><div><p> case.
1324 setHasMarginAfterQuirk(true);
1325 }
1326}
1327
1328void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1329{
1330 marginInfo.setAtAfterSideOfBlock(true);
1331
robert@webkit.org97037ef2013-11-20 19:26:10 +00001332 // If our last child was a self-collapsing block with clearance then our logical height is flush with the
1333 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want
1334 // to perform now is at the child's margin-top - so adjust our height to that position.
1335 RenderObject* lastBlock = lastChild();
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001336 if (is<RenderBlockFlow>(lastBlock) && downcast<RenderBlockFlow>(*lastBlock).isSelfCollapsingBlock())
1337 setLogicalHeight(logicalHeight() - downcast<RenderBlockFlow>(*lastBlock).marginOffsetForSelfCollapsingBlock());
robert@webkit.org97037ef2013-11-20 19:26:10 +00001338
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001339 // If we can't collapse with children then add in the bottom margin.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001340 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1341 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1342 setLogicalHeight(logicalHeight() + marginInfo.margin());
1343
1344 // Now add in our bottom border/padding.
1345 setLogicalHeight(logicalHeight() + afterSide);
1346
1347 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1348 // If this happens, ensure that the computed height is increased to the minimal height.
andersca@apple.com86298632013-11-10 19:32:33 +00001349 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001350
1351 // Update our bottom collapsed margin info.
1352 setCollapsedBottomMargin(marginInfo);
1353}
1354
1355void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1356{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001357 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001358 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001359 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001360 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001361 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001362
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001363 rareBlockFlowData()->m_margins.setPositiveMarginBefore(pos);
1364 rareBlockFlowData()->m_margins.setNegativeMarginBefore(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001365}
1366
1367void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1368{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001369 if (!hasRareBlockFlowData()) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001370 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(*this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(*this))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001371 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001372 materializeRareBlockFlowData();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001373 }
weinig@apple.com924a77a2013-11-11 00:22:38 +00001374
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001375 rareBlockFlowData()->m_margins.setPositiveMarginAfter(pos);
1376 rareBlockFlowData()->m_margins.setNegativeMarginAfter(neg);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001377}
1378
1379void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1380{
akling@apple.com827be9c2013-10-29 02:58:43 +00001381 if (style().marginBeforeCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001382 ASSERT(value);
1383 return;
1384 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001385
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001386 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001387 if (!value)
1388 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001389 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001390 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001391
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001392 rareBlockFlowData()->m_discardMarginBefore = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001393}
1394
1395void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1396{
akling@apple.com827be9c2013-10-29 02:58:43 +00001397 if (style().marginAfterCollapse() == MDISCARD) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001398 ASSERT(value);
1399 return;
1400 }
1401
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001402 if (!hasRareBlockFlowData()) {
weinig@apple.com924a77a2013-11-11 00:22:38 +00001403 if (!value)
1404 return;
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001405 materializeRareBlockFlowData();
weinig@apple.com924a77a2013-11-11 00:22:38 +00001406 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001407
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001408 rareBlockFlowData()->m_discardMarginAfter = value;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001409}
1410
1411bool RenderBlockFlow::mustDiscardMarginBefore() const
1412{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001413 return style().marginBeforeCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginBefore);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001414}
1415
1416bool RenderBlockFlow::mustDiscardMarginAfter() const
1417{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001418 return style().marginAfterCollapse() == MDISCARD || (hasRareBlockFlowData() && rareBlockFlowData()->m_discardMarginAfter);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001419}
1420
weinig@apple.com12840dc2013-10-22 23:59:08 +00001421bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001422{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001423 ASSERT(!child.selfNeedsLayout());
1424 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001425 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001426 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001427 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001428
1429 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1430 // In case the boxes are perpendicular we assume the property is not specified.
1431 return false;
1432}
1433
weinig@apple.com12840dc2013-10-22 23:59:08 +00001434bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001435{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001436 ASSERT(!child.selfNeedsLayout());
1437 if (!child.isWritingModeRoot())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001438 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginAfter() : (child.style().marginAfterCollapse() == MDISCARD);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001439 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001440 return is<RenderBlockFlow>(child) ? downcast<RenderBlockFlow>(child).mustDiscardMarginBefore() : (child.style().marginBeforeCollapse() == MDISCARD);
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 +00001446bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001447{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001448 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001449 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001450 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001451 return childStyle.marginBeforeCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001452 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001453 return childStyle.marginAfterCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001454
1455 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1456 return false;
1457}
1458
weinig@apple.com12840dc2013-10-22 23:59:08 +00001459bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox& child) const
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001460{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001461 ASSERT(!child.selfNeedsLayout());
akling@apple.com827be9c2013-10-29 02:58:43 +00001462 const RenderStyle& childStyle = child.style();
weinig@apple.com12840dc2013-10-22 23:59:08 +00001463 if (!child.isWritingModeRoot())
akling@apple.com827be9c2013-10-29 02:58:43 +00001464 return childStyle.marginAfterCollapse() == MSEPARATE;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001465 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
akling@apple.com827be9c2013-10-29 02:58:43 +00001466 return childStyle.marginBeforeCollapse() == MSEPARATE;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001467
1468 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1469 return false;
1470}
1471
weinig@apple.com12840dc2013-10-22 23:59:08 +00001472static bool inNormalFlow(RenderBox& child)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001473{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001474 RenderBlock* curr = child.containingBlock();
1475 while (curr && curr != &child.view()) {
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001476 if (curr->isRenderFlowThread())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001477 return true;
1478 if (curr->isFloatingOrOutOfFlowPositioned())
1479 return false;
1480 curr = curr->containingBlock();
1481 }
1482 return true;
1483}
1484
weinig@apple.com12840dc2013-10-22 23:59:08 +00001485LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox& child, LayoutUnit logicalOffset)
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 checkBeforeAlways = (checkColumnBreaks && child.style().columnBreakBefore() == PBALWAYS)
1494 || (checkPageBreaks && child.style().pageBreakBefore() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001495 || (checkRegionBreaks && child.style().regionBreakBefore() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001496 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001497 if (checkColumnBreaks) {
1498 if (isInsideMulticolFlowThread)
1499 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001500 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001501 if (checkRegionBreaks) {
1502 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001503 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, &child, true, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001504 return logicalOffset + offsetBreakAdjustment;
1505 }
1506 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1507 }
1508 return logicalOffset;
1509}
1510
weinig@apple.com12840dc2013-10-22 23:59:08 +00001511LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox& child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001512{
1513 // FIXME: Add page break checking here when we support printing.
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001514 RenderFlowThread* flowThread = flowThreadContainingBlock();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001515 bool isInsideMulticolFlowThread = flowThread && !flowThread->isRenderNamedFlowThread();
hyatt@apple.com73715ca2014-05-06 21:35:52 +00001516 bool checkColumnBreaks = flowThread && flowThread->shouldCheckColumnBreaks();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001517 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 +00001518 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001519 bool checkAfterAlways = (checkColumnBreaks && child.style().columnBreakAfter() == PBALWAYS)
1520 || (checkPageBreaks && child.style().pageBreakAfter() == PBALWAYS)
akling@apple.com827be9c2013-10-29 02:58:43 +00001521 || (checkRegionBreaks && child.style().regionBreakAfter() == PBALWAYS);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001522 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1523 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1524
1525 // So our margin doesn't participate in the next collapsing steps.
1526 marginInfo.clearMargin();
1527
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001528 if (checkColumnBreaks) {
1529 if (isInsideMulticolFlowThread)
1530 checkRegionBreaks = true;
commit-queue@webkit.orgfd8f1a22014-01-20 19:55:59 +00001531 }
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001532 if (checkRegionBreaks) {
1533 LayoutUnit offsetBreakAdjustment = 0;
weinig@apple.com12840dc2013-10-22 23:59:08 +00001534 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, &child, false, &offsetBreakAdjustment))
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001535 return logicalOffset + marginOffset + offsetBreakAdjustment;
1536 }
1537 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1538 }
1539 return logicalOffset;
1540}
1541
weinig@apple.com12840dc2013-10-22 23:59:08 +00001542LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox& child, bool atBeforeSideOfBlock)
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001543{
cdumez@apple.come9437792014-10-08 23:33:43 +00001544 RenderBlock* childRenderBlock = is<RenderBlock>(child) ? &downcast<RenderBlock>(child) : nullptr;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001545
1546 if (estimateWithoutPagination != logicalTopAfterClear) {
1547 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1548 // position.
1549 setLogicalHeight(logicalTopAfterClear);
1550 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1551
weinig@apple.com12840dc2013-10-22 23:59:08 +00001552 if (child.shrinkToAvoidFloats()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001553 // The child's width depends on the line width. When the child shifts to clear an item, its width can
1554 // change (because it has more available line width). So mark the item as dirty.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001555 child.setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001556 }
1557
1558 if (childRenderBlock) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00001559 if (!child.avoidsFloats() && childRenderBlock->containsFloats())
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00001560 downcast<RenderBlockFlow>(*childRenderBlock).markAllDescendantsWithFloatsForLayout();
hyatt@apple.comccad3742015-02-04 21:39:00 +00001561 child.markForPaginationRelayoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001562 }
1563
1564 // Our guess was wrong. Make the child lay itself out again.
weinig@apple.com12840dc2013-10-22 23:59:08 +00001565 child.layoutIfNeeded();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001566 }
1567
1568 LayoutUnit oldTop = logicalTopAfterClear;
1569
1570 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1571 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1572
1573 if (pageLogicalHeightForOffset(result)) {
1574 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
weinig@apple.com12840dc2013-10-22 23:59:08 +00001575 LayoutUnit spaceShortage = child.logicalHeight() - remainingLogicalHeight;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001576 if (spaceShortage > 0) {
1577 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1578 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1579 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1580 // This should be improved, though, because here we just pretend that the child is
1581 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1582 // where there's no child content, border or padding. In other words, we risk stretching more
1583 // than necessary.
1584 setPageBreak(result, spaceShortage);
1585 }
1586 }
1587
1588 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1589 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1590 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1591
1592 LayoutUnit paginationStrut = 0;
1593 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1594 if (unsplittableAdjustmentDelta)
1595 paginationStrut = unsplittableAdjustmentDelta;
1596 else if (childRenderBlock && childRenderBlock->paginationStrut())
1597 paginationStrut = childRenderBlock->paginationStrut();
1598
1599 if (paginationStrut) {
1600 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1601 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1602 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1603 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1604 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1605 // and pushes to the next page anyway, so not too concerned about it.
1606 setPaginationStrut(result + paginationStrut);
1607 if (childRenderBlock)
1608 childRenderBlock->setPaginationStrut(0);
1609 } else
1610 result += paginationStrut;
1611 }
1612
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00001613 // 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 +00001614 setLogicalHeight(logicalHeight() + (result - oldTop));
1615
1616 // Return the final adjusted logical top.
1617 return result;
1618}
1619
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001620static inline LayoutUnit calculateMinimumPageHeight(RenderStyle& renderStyle, RootInlineBox& lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001621{
1622 // We may require a certain minimum number of lines per page in order to satisfy
1623 // orphans and widows, and that may affect the minimum page height.
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001624 unsigned lineCount = std::max<unsigned>(renderStyle.hasAutoOrphans() ? 1 : renderStyle.orphans(), renderStyle.hasAutoWidows() ? 1 : renderStyle.widows());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001625 if (lineCount > 1) {
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001626 RootInlineBox* line = &lastLine;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001627 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1628 line = line->prevRootBox();
1629
1630 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1631 // adjustLinePositionForPagination() for more details.
1632 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001633 lineTop = std::min(line->lineTopWithLeading(), overflow.y());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001634 }
1635 return lineBottom - lineTop;
1636}
1637
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001638static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox)
1639{
bfulgham@apple.com62729772015-04-29 02:26:07 +00001640 const auto& renderer = lineBox.renderer();
1641
1642 if (!renderer.document().settings())
1643 return false;
1644
1645 if (!renderer.document().settings()->appleMailPaginationQuirkEnabled())
1646 return false;
1647
1648 if (renderer.element() && renderer.element()->idForStyleResolution() == AtomicString("messageContentContainer", AtomicString::ConstructFromLiteral))
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001649 return true;
1650
1651 return false;
1652}
1653
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001654void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread)
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001655{
hyatt@apple.com9a79c622015-09-15 18:38:18 +00001656 // FIXME: Ignore anonymous inline blocks. Handle the delta already having been set because of
1657 // collapsing margins from a previous anonymous inline block.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001658 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1659 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1660 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1661 // of the first column.
1662 //
1663 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1664 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1665 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1666 // for overflow to occur), and then cache visible overflow for each column rect.
1667 //
1668 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1669 // content that paints in a previous column (and content that paints in the following column).
1670 //
1671 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1672 // at least make positive leading work in typical cases.
1673 //
1674 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1675 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1676 // line and all following lines.
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001677 overflowsRegion = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001678 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
andersca@apple.com86298632013-11-10 19:32:33 +00001679 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1680 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001681 LayoutUnit lineHeight = logicalBottom - logicalOffset;
mmaxfield@apple.comf8e26e72014-10-30 21:39:27 +00001682 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), *lineBox, logicalOffset, logicalBottom));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001683 logicalOffset += delta;
1684 lineBox->setPaginationStrut(0);
1685 lineBox->setIsFirstAfterPageBreak(false);
1686 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1687 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1688 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1689 // still going to add a strut, so that the visible overflow fits on a single page.
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001690 if (!pageLogicalHeight || !hasNextPage(logicalOffset)) {
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001691 // 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.
1692 // 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 +00001693 return;
hyatt@apple.comcb5ab702014-11-19 23:40:23 +00001694 }
1695
1696 if (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) {
1697 // 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
1698 // line and computing a new height that excludes anything we consider "blank space". We will discard margins, descent, and even overflow. If we are
1699 // 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
1700 // top of the page.
1701 // 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
1702 // this will be a real-world issue. For now we don't try to deal with this problem.
1703 logicalOffset = intMaxForLayoutUnit;
1704 logicalBottom = intMinForLayoutUnit;
1705 lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom);
1706 lineHeight = logicalBottom - logicalOffset;
1707 if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight)
1708 return; // Give up. We're genuinely too big even after excluding blank space and overflow.
1709 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1710 }
1711
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001712 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001713 overflowsRegion = (lineHeight > remainingLogicalHeight);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001714
1715 int lineIndex = lineCount(lineBox);
1716 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001717 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001718 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001719 setDidBreakAtLineToAvoidWidow();
1720 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001721 // If we have a non-uniform page height, then we have to shift further possibly.
1722 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1723 return;
1724 if (lineHeight > pageLogicalHeight) {
1725 // Split the top margin in order to avoid splitting the visible part of the line.
andersca@apple.com86298632013-11-10 19:32:33 +00001726 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001727 }
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001728 LayoutUnit remainingLogicalHeightAtNewOffset = pageRemainingLogicalHeightForOffset(logicalOffset + remainingLogicalHeight, ExcludePageBoundary);
1729 overflowsRegion = (lineHeight > remainingLogicalHeightAtNewOffset);
andersca@apple.com86298632013-11-10 19:32:33 +00001730 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001731 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1732 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
akling@apple.com827be9c2013-10-29 02:58:43 +00001733 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style().hasAutoOrphans() && style().orphans() >= lineIndex))
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001734 && !isOutOfFlowPositioned() && !isTableCell()) {
1735 auto firstRootBox = this->firstRootBox();
1736 auto firstRootBoxOverflowRect = firstRootBox->logicalVisualOverflowRect(firstRootBox->lineTop(), firstRootBox->lineBottom());
1737 auto firstLineUpperOverhang = std::max(-firstRootBoxOverflowRect.y(), LayoutUnit());
bfulgham@apple.comb5953432015-02-13 21:56:01 +00001738 if (needsAppleMailPaginationQuirk(*lineBox))
1739 return;
mmaxfield@apple.com4d7e9a22014-11-18 22:40:29 +00001740 setPaginationStrut(remainingLogicalHeight + logicalOffset + firstLineUpperOverhang);
1741 } else {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001742 delta += remainingLogicalHeight;
1743 lineBox->setPaginationStrut(remainingLogicalHeight);
1744 lineBox->setIsFirstAfterPageBreak(true);
1745 }
commit-queue@webkit.org883b01c2014-01-20 08:58:36 +00001746 } else if (remainingLogicalHeight == pageLogicalHeight) {
1747 // We're at the very top of a page or column.
1748 if (lineBox != firstRootBox())
1749 lineBox->setIsFirstAfterPageBreak(true);
1750 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
1751 setPageBreak(logicalOffset, lineHeight);
1752 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001753}
1754
1755void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1756{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001757 ASSERT(lineToBreak >= 0);
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001758 ASSERT(!ensureRareBlockFlowData().m_didBreakAtLineToAvoidWidow);
1759 ensureRareBlockFlowData().m_lineBreakToAvoidWidow = lineToBreak;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001760}
1761
abucur@adobe.comfc497132013-10-04 08:49:21 +00001762void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1763{
1764 ASSERT(!shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001765 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001766 return;
1767
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001768 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = true;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001769}
1770
1771void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1772{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001773 if (!hasRareBlockFlowData())
abucur@adobe.comfc497132013-10-04 08:49:21 +00001774 return;
1775
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001776 rareBlockFlowData()->m_didBreakAtLineToAvoidWidow = false;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001777}
1778
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001779void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1780{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001781 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001782 if (!hasRareBlockFlowData())
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001783 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001784
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00001785 rareBlockFlowData()->m_lineBreakToAvoidWidow = -1;
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001786}
1787
1788bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1789{
1790 if (!shouldBreakAtLineToAvoidWidow())
1791 return false;
1792
1793 statePusher.pop();
1794 setEverHadLayout(true);
1795 layoutBlock(false);
1796 return true;
1797}
1798
weinig@apple.com31324fd2013-10-28 19:22:51 +00001799bool RenderBlockFlow::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1800{
1801 ASSERT(view().layoutState() && view().layoutState()->isPaginated());
1802
1803 RenderFlowThread* flowThread = flowThreadContainingBlock();
1804 if (!flowThread)
1805 return true; // Printing and multi-column both make new pages to accommodate content.
1806
1807 // See if we're in the last region.
1808 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001809 RenderRegion* region = flowThread->regionAtBlockOffset(this, pageOffset, true);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001810 if (!region)
1811 return false;
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001812
weinig@apple.com31324fd2013-10-28 19:22:51 +00001813 if (region->isLastRegion())
akling@apple.com827be9c2013-10-29 02:58:43 +00001814 return region->isRenderRegionSet() || region->style().regionFragment() == BreakRegionFragment
weinig@apple.com31324fd2013-10-28 19:22:51 +00001815 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001816
mihnea@adobe.comc191b0a2014-03-19 12:38:51 +00001817 RenderRegion* startRegion = nullptr;
1818 RenderRegion* endRegion = nullptr;
stavila@adobe.com6cb976d2013-11-21 06:57:19 +00001819 flowThread->getRegionRangeForBox(this, startRegion, endRegion);
stavila@adobe.come1efa7f2014-05-20 14:34:56 +00001820 return (endRegion && region != endRegion);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001821}
1822
1823LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox& child, LayoutUnit logicalOffset, bool includeMargins)
1824{
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001825 if (!childBoxIsUnsplittableForFragmentation(child))
weinig@apple.com31324fd2013-10-28 19:22:51 +00001826 return logicalOffset;
abucur@adobe.com4cddad82014-03-19 06:57:17 +00001827
1828 RenderFlowThread* flowThread = flowThreadContainingBlock();
weinig@apple.com31324fd2013-10-28 19:22:51 +00001829 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
1830 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1831 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1832 updateMinimumPageHeight(logicalOffset, childLogicalHeight);
1833 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
1834 || !hasNextPage(logicalOffset))
1835 return logicalOffset;
1836 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1837 if (remainingLogicalHeight < childLogicalHeight) {
1838 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
1839 return logicalOffset;
1840 return logicalOffset + remainingLogicalHeight;
1841 }
1842 return logicalOffset;
1843}
1844
1845bool RenderBlockFlow::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
1846{
1847 bool checkRegion = false;
1848 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
1849 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
1850 if (minimumLogicalHeight <= pageLogicalHeight)
1851 return true;
1852 if (!hasNextPage(logicalOffset + adjustment))
1853 return false;
1854 adjustment += pageLogicalHeight;
1855 checkRegion = true;
1856 }
1857 return !checkRegion;
1858}
1859
1860void RenderBlockFlow::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
1861{
1862 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1863 flowThread->setPageBreak(this, offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
1864}
1865
1866void RenderBlockFlow::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
1867{
1868 if (RenderFlowThread* flowThread = flowThreadContainingBlock())
1869 flowThread->updateMinimumPageHeight(this, offsetFromLogicalTopOfFirstPage() + offset, minHeight);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001870}
1871
1872LayoutUnit RenderBlockFlow::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
1873{
1874 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1875 if (!pageLogicalHeight)
1876 return logicalOffset;
1877
1878 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
1879 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
1880 if (pageBoundaryRule == ExcludePageBoundary)
1881 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
1882 return logicalOffset + remainingLogicalHeight;
1883}
1884
1885LayoutUnit RenderBlockFlow::pageLogicalTopForOffset(LayoutUnit offset) const
1886{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001887 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1888 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1889 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1890 if (!pageLogicalHeight)
1891 return 0;
1892
weinig@apple.com31324fd2013-10-28 19:22:51 +00001893 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_pageOffset.height() : view().layoutState()->m_pageOffset.width();
1894 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? view().layoutState()->m_layoutOffset.height() : view().layoutState()->m_layoutOffset.width();
1895
1896 LayoutUnit cumulativeOffset = offset + blockLogicalTop;
1897 RenderFlowThread* flowThread = flowThreadContainingBlock();
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001898 if (!flowThread)
weinig@apple.com31324fd2013-10-28 19:22:51 +00001899 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
hyatt@apple.com150e7f22014-02-11 16:51:45 +00001900 return firstPageLogicalTop + flowThread->pageLogicalTopForOffset(cumulativeOffset - firstPageLogicalTop);
weinig@apple.com31324fd2013-10-28 19:22:51 +00001901}
1902
1903LayoutUnit RenderBlockFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
1904{
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001905 // Unsplittable objects clear out the pageLogicalHeight in the layout state as a way of signaling that no
1906 // pagination should occur. Therefore we have to check this first and bail if the value has been set to 0.
1907 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1908 if (!pageLogicalHeight)
1909 return 0;
1910
1911 // Now check for a flow thread.
weinig@apple.com31324fd2013-10-28 19:22:51 +00001912 RenderFlowThread* flowThread = flowThreadContainingBlock();
1913 if (!flowThread)
hyatt@apple.com6c9d5d32015-02-19 21:42:21 +00001914 return pageLogicalHeight;
weinig@apple.com31324fd2013-10-28 19:22:51 +00001915 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
1916}
1917
1918LayoutUnit RenderBlockFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
1919{
1920 offset += offsetFromLogicalTopOfFirstPage();
1921
1922 RenderFlowThread* flowThread = flowThreadContainingBlock();
1923 if (!flowThread) {
1924 LayoutUnit pageLogicalHeight = view().layoutState()->m_pageLogicalHeight;
1925 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
1926 if (pageBoundaryRule == IncludePageBoundary) {
1927 // If includeBoundaryPoint is true the line exactly on the top edge of a
1928 // column will act as being part of the previous column.
1929 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
1930 }
1931 return remainingHeight;
1932 }
1933
1934 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
1935}
1936
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00001937LayoutUnit RenderBlockFlow::logicalHeightForChildForFragmentation(const RenderBox& child) const
1938{
1939 // This method is required because regions do not fragment monolithic elements but instead
1940 // they let them overflow the region they flow in. This behaviour is different from the
1941 // multicol/printing implementations, which have not yet been updated to correctly handle
1942 // monolithic elements.
1943 // As a result, for the moment, this method will only be used for regions, the multicol and
1944 // printing implementations will stick to the existing behaviour until their fragmentation
1945 // implementation is updated to match the regions implementation.
1946 if (!flowThreadContainingBlock() || !flowThreadContainingBlock()->isRenderNamedFlowThread())
1947 return logicalHeightForChild(child);
1948
1949 // For unsplittable elements, this method will just return the height of the element that
1950 // fits into the current region, without the height of the part that overflows the region.
1951 // This is done for all regions, except the last one because in that case, the logical
1952 // height of the flow thread needs to also
1953 if (!childBoxIsUnsplittableForFragmentation(child) || !pageLogicalHeightForOffset(logicalTopForChild(child)))
1954 return logicalHeightForChild(child);
1955
1956 // If we're on the last page this block fragments to, the logical height of the flow thread must include
1957 // the entire unsplittable child because any following children will not be moved to the next page
1958 // so they will need to be laid out below the current unsplittable child.
1959 LayoutUnit childLogicalTop = logicalTopForChild(child);
1960 if (!hasNextPage(childLogicalTop))
1961 return logicalHeightForChild(child);
1962
1963 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(childLogicalTop, ExcludePageBoundary);
1964 return std::min(child.logicalHeight(), remainingLogicalHeight);
1965}
weinig@apple.com31324fd2013-10-28 19:22:51 +00001966
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001967void RenderBlockFlow::layoutLineGridBox()
1968{
akling@apple.com827be9c2013-10-29 02:58:43 +00001969 if (style().lineGrid() == RenderStyle::initialLineGrid()) {
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001970 setLineGridBox(0);
1971 return;
1972 }
1973
1974 setLineGridBox(0);
1975
akling@apple.com1aa97b02013-10-31 21:59:49 +00001976 auto lineGridBox = std::make_unique<RootInlineBox>(*this);
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001977 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1978 lineGridBox->setConstructed();
1979 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1980 VerticalPositionCache verticalPositionCache;
1981 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1982
aestes@apple.com13aae082016-01-02 08:03:08 +00001983 setLineGridBox(WTFMove(lineGridBox));
akling@apple.com1aa97b02013-10-31 21:59:49 +00001984
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001985 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1986 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1987 // to this grid.
1988}
1989
weinig@apple.com12840dc2013-10-22 23:59:08 +00001990bool RenderBlockFlow::containsFloat(RenderBox& renderer) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001991{
weinig@apple.com12840dc2013-10-22 23:59:08 +00001992 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001993}
1994
1995void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1996{
1997 RenderBlock::styleDidChange(diff, oldStyle);
1998
1999 // After our style changed, if we lose our ability to propagate floats into next sibling
2000 // blocks, then we need to find the top most parent containing that overhanging float and
2001 // then mark its descendants with floats for layout and clear all floats from its next
2002 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
2003 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
2004 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
2005 RenderBlockFlow* parentBlock = this;
2006 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002007
weinig@apple.comc77041e2013-12-14 18:05:45 +00002008 for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(*this)) {
2009 if (ancestor.isRenderView())
akling@apple.comf3028052013-11-04 08:46:06 +00002010 break;
weinig@apple.comc77041e2013-12-14 18:05:45 +00002011 if (ancestor.hasOverhangingFloats()) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002012 for (auto it = floatingObjectSet.begin(), end = floatingObjectSet.end(); it != end; ++it) {
2013 RenderBox& renderer = (*it)->renderer();
weinig@apple.comc77041e2013-12-14 18:05:45 +00002014 if (ancestor.hasOverhangingFloat(renderer)) {
2015 parentBlock = &ancestor;
akling@apple.comf3028052013-11-04 08:46:06 +00002016 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002017 }
2018 }
2019 }
2020 }
2021
2022 parentBlock->markAllDescendantsWithFloatsForLayout();
2023 parentBlock->markSiblingsWithFloatsForLayout();
2024 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00002025
akling@apple.com8f40c5b2013-10-27 22:54:07 +00002026 if (auto fragment = renderNamedFlowFragment())
akling@apple.com827be9c2013-10-29 02:58:43 +00002027 fragment->setStyle(RenderNamedFlowFragment::createStyle(style()));
antti@apple.com42fb53d2013-10-25 02:33:11 +00002028
antti@apple.com9e891c82014-05-22 06:12:34 +00002029 if (diff >= StyleDifferenceRepaint) {
2030 // FIXME: This could use a cheaper style-only test instead of SimpleLineLayout::canUseFor.
2031 if (selfNeedsLayout() || !m_simpleLineLayout || !SimpleLineLayout::canUseFor(*this))
2032 invalidateLineLayoutPath();
2033 }
2034
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002035 if (multiColumnFlowThread())
2036 updateStylesForColumnChildren();
2037}
2038
2039void RenderBlockFlow::updateStylesForColumnChildren()
2040{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002041 for (auto* child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
hyatt@apple.comfdb12812014-06-23 18:56:52 +00002042 child->setStyle(RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002043}
2044
akling@apple.combdae43242013-10-25 12:00:20 +00002045void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002046{
akling@apple.com827be9c2013-10-29 02:58:43 +00002047 const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002048 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
2049
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002050 if (oldStyle) {
2051 EPosition oldPosition = oldStyle->position();
2052 EPosition newPosition = newStyle.position();
abucur@adobe.comc0a88a62014-10-16 06:50:30 +00002053
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002054 if (parent() && diff == StyleDifferenceLayout && oldPosition != newPosition) {
2055 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
2056 markAllDescendantsWithFloatsForLayout();
stavila@adobe.comd40a2dc2014-06-23 14:59:48 +00002057 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002058 }
2059
2060 RenderBlock::styleWillChange(diff, newStyle);
2061}
2062
antti@apple.coma2c7f242013-10-22 22:37:25 +00002063void RenderBlockFlow::deleteLines()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002064{
2065 if (containsFloats())
2066 m_floatingObjects->clearLineBoxTreePointers();
weinig@apple.com611b9292013-10-20 22:57:54 +00002067
antti@apple.comfea51992013-10-28 13:39:23 +00002068 if (m_simpleLineLayout) {
antti@apple.com940f5872013-10-24 20:31:11 +00002069 ASSERT(!m_lineBoxes.firstLineBox());
antti@apple.comfea51992013-10-28 13:39:23 +00002070 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00002071 } else
akling@apple.com31dd4f42013-10-30 22:27:59 +00002072 m_lineBoxes.deleteLineBoxTree();
weinig@apple.com611b9292013-10-20 22:57:54 +00002073
antti@apple.coma2c7f242013-10-22 22:37:25 +00002074 RenderBlock::deleteLines();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002075}
2076
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002077void RenderBlockFlow::moveFloatsTo(RenderBlockFlow* toBlockFlow)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002078{
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002079 // When a portion of the render tree is being detached, anonymous blocks
2080 // will be combined as their children are deleted. In this process, the
2081 // anonymous block later in the tree is merged into the one preceeding it.
2082 // It can happen that the later block (this) contains floats that the
2083 // previous block (toBlockFlow) did not contain, and thus are not in the
2084 // floating objects list for toBlockFlow. This can result in toBlockFlow
2085 // containing floats that are not in it's floating objects list, but are in
2086 // the floating objects lists of siblings and parents. This can cause
2087 // problems when the float itself is deleted, since the deletion code
2088 // assumes that if a float is not in it's containing block's floating
2089 // objects list, it isn't in any floating objects list. In order to
2090 // preserve this condition (removing it has serious performance
2091 // implications), we need to copy the floating objects from the old block
2092 // (this) to the new block (toBlockFlow). The float's metrics will likely
2093 // all be wrong, but since toBlockFlow is already marked for layout, this
2094 // will get fixed before anything gets displayed.
2095 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
2096 if (m_floatingObjects) {
2097 if (!toBlockFlow->m_floatingObjects)
2098 toBlockFlow->createFloatingObjects();
2099
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002100 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
2101 auto end = fromFloatingObjectSet.end();
2102
2103 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
2104 FloatingObject* floatingObject = it->get();
2105
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002106 // Don't insert the object again if it's already in the list
weinig@apple.com12840dc2013-10-22 23:59:08 +00002107 if (toBlockFlow->containsFloat(floatingObject->renderer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002108 continue;
2109
2110 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
2111 }
2112 }
2113}
2114
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002115void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock& toBlock, bool fullRemoveInsert)
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002116{
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002117 RenderBlockFlow& toBlockFlow = downcast<RenderBlockFlow>(toBlock);
2118 moveAllChildrenTo(&toBlockFlow, fullRemoveInsert);
2119 moveFloatsTo(&toBlockFlow);
jhoneycutt@apple.com5ad82202014-02-18 22:55:39 +00002120}
2121
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002122void RenderBlockFlow::addOverflowFromFloats()
2123{
2124 if (!m_floatingObjects)
2125 return;
2126
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002127 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2128 auto end = floatingObjectSet.end();
2129 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002130 const auto& floatingObject = *it->get();
2131 if (floatingObject.isDescendant())
2132 addOverflowFromChild(&floatingObject.renderer(), IntSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002133 }
2134}
2135
2136void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
2137{
2138 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
2139
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002140 if (!multiColumnFlowThread() && (recomputeFloats || createsNewFormattingContext() || hasSelfPaintingLayer()))
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002141 addOverflowFromFloats();
2142}
2143
2144void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
2145{
2146 // Repaint any overhanging floats (if we know we're the one to paint them).
2147 // Otherwise, bail out.
2148 if (!hasOverhangingFloats())
2149 return;
2150
2151 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2152 // in this block. Better yet would be to push extra state for the containers of other floats.
zalan@apple.com163bc1c2015-08-12 03:41:40 +00002153 LayoutStateDisabler layoutStateDisabler(view());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002154 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2155 auto end = floatingObjectSet.end();
2156 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002157 const auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002158 // Only repaint the object if it is overhanging, is not in its own layer, and
2159 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2160 // condition is replaced with being a descendant of us.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002161 auto& renderer = floatingObject.renderer();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002162 if (logicalBottomForFloat(floatingObject) > logicalHeight()
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002163 && !renderer.hasSelfPaintingLayer()
2164 && (floatingObject.shouldPaint() || (paintAllDescendants && renderer.isDescendantOf(this)))) {
2165 renderer.repaint();
2166 renderer.repaintOverhangingFloats(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002167 }
2168 }
2169}
2170
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002171void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002172{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002173 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002174
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002175 if (!multiColumnFlowThread() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002176 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002177
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002178 // Iterate over our children and paint the column rules as needed.
2179 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2180 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2181 columnSet.paintColumnRules(paintInfo, childPoint);
2182 }
2183}
2184
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002185void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2186{
2187 if (!m_floatingObjects)
2188 return;
2189
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002190 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2191 auto end = floatingObjectSet.end();
2192 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002193 const auto& floatingObject = *it->get();
2194 auto& renderer = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002195 // Only paint the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002196 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002197 PaintInfo currentPaintInfo(paintInfo);
2198 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2199 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
zalan@apple.com6816b132015-10-17 19:14:53 +00002200 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject,
2201 LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(floatingObject) - renderer.x(),
2202 paintOffset.y() + yPositionForFloatIncludingMargin(floatingObject) - renderer.y()));
2203 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002204 if (!preservePhase) {
2205 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
zalan@apple.com6816b132015-10-17 19:14:53 +00002206 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002207 currentPaintInfo.phase = PaintPhaseFloat;
zalan@apple.com6816b132015-10-17 19:14:53 +00002208 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002209 currentPaintInfo.phase = PaintPhaseForeground;
zalan@apple.com6816b132015-10-17 19:14:53 +00002210 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002211 currentPaintInfo.phase = PaintPhaseOutline;
zalan@apple.com6816b132015-10-17 19:14:53 +00002212 renderer.paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002213 }
2214 }
2215 }
2216}
2217
weinig@apple.com12840dc2013-10-22 23:59:08 +00002218void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002219{
2220 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002221 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2222 auto end = floatingObjectSet.end();
2223 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002224 const auto& floatingObject = *it->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002225 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2226 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
zalan@apple.com6816b132015-10-17 19:14:53 +00002227 floatingObject.renderer().width(), floatingObject.renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002228 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002229 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002230 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002231 }
2232 }
2233}
2234
2235void RenderBlockFlow::createFloatingObjects()
2236{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002237 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002238}
2239
2240void RenderBlockFlow::removeFloatingObjects()
2241{
2242 if (!m_floatingObjects)
2243 return;
2244
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002245 markSiblingsWithFloatsForLayout();
2246
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002247 m_floatingObjects->clear();
2248}
2249
weinig@apple.com12840dc2013-10-22 23:59:08 +00002250FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002251{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002252 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002253
2254 // Create the list of special objects if we don't aleady have one
2255 if (!m_floatingObjects)
2256 createFloatingObjects();
2257 else {
2258 // Don't insert the floatingObject again if it's already in the list
2259 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002260 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002261 if (it != floatingObjectSet.end())
2262 return it->get();
2263 }
2264
2265 // Create the special floatingObject entry & append it to the list
2266
weinig@apple.com12840dc2013-10-22 23:59:08 +00002267 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002268
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002269 // 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 +00002270 bool isChildRenderBlock = floatBox.isRenderBlock();
2271 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2272 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002273
2274 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002275 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2276 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002277 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002278 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2279 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002280 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002281 floatBox.updateLogicalWidth();
2282 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002283 }
2284
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002285 setLogicalWidthForFloat(*floatingObject, logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002286
aestes@apple.com13aae082016-01-02 08:03:08 +00002287 return m_floatingObjects->add(WTFMove(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002288}
2289
weinig@apple.com12840dc2013-10-22 23:59:08 +00002290void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002291{
2292 if (m_floatingObjects) {
2293 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002294 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002295 if (it != floatingObjectSet.end()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002296 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002297 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002298 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2299 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002300
2301 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2302 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2303 logicalBottom = LayoutUnit::max();
2304 else {
2305 // Special-case zero- and less-than-zero-height floats: those don't touch
2306 // the line that they're on, but it still needs to be dirtied. This is
2307 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002308 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002309 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002310 if (floatingObject.originatingLine()) {
2311 floatingObject.originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002312 if (!selfNeedsLayout()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002313 ASSERT(&floatingObject.originatingLine()->renderer() == this);
2314 floatingObject.originatingLine()->markDirty();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002315 }
2316#if !ASSERT_DISABLED
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002317 floatingObject.setOriginatingLine(0);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002318#endif
2319 }
2320 markLinesDirtyInBlockRange(0, logicalBottom);
2321 }
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002322 m_floatingObjects->remove(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002323 }
2324 }
2325}
2326
2327void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2328{
2329 if (!containsFloats())
2330 return;
2331
2332 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2333 FloatingObject* curr = floatingObjectSet.last().get();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002334 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(*curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002335 m_floatingObjects->remove(curr);
2336 if (floatingObjectSet.isEmpty())
2337 break;
2338 curr = floatingObjectSet.last().get();
2339 }
2340}
2341
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002342LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2343{
2344 LayoutUnit offset = fixedOffset;
2345 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2346 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2347 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2348}
2349
2350LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2351{
2352 LayoutUnit offset = fixedOffset;
2353 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2354 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2355 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2356}
2357
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002358LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject& floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002359{
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002360 auto& childBox = floatingObject.renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002361 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002362 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002363
andersca@apple.com86298632013-11-10 19:32:33 +00002364 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002365
2366 LayoutUnit floatLogicalLeft;
2367
2368 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002369 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2370
2371 if (isInitialLetter) {
2372 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2373 if (letterClearance > 0) {
2374 logicalTopOffset += letterClearance;
2375 setLogicalHeight(logicalHeight() + letterClearance);
2376 }
2377 }
2378
akling@apple.com827be9c2013-10-29 02:58:43 +00002379 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002380 LayoutUnit heightRemainingLeft = 1;
2381 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002382 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2383 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002384 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002385 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002386 if (insideFlowThread) {
2387 // Have to re-evaluate all of our offsets, since they may have changed.
2388 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2389 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002390 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002391 }
2392 }
andersca@apple.com86298632013-11-10 19:32:33 +00002393 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002394 } else {
2395 LayoutUnit heightRemainingLeft = 1;
2396 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002397 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2398 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002399 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002400 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002401 if (insideFlowThread) {
2402 // Have to re-evaluate all of our offsets, since they may have changed.
2403 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2404 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002405 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002406 }
2407 }
2408 // Use the original width of the float here, since the local variable
2409 // |floatLogicalWidth| was capped to the available line width. See
2410 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002411 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002412 }
2413
hyatt@apple.com87515262014-09-04 21:20:12 +00002414 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002415 const RenderStyle& style = firstLineStyle();
2416 const FontMetrics& fontMetrics = style.fontMetrics();
2417 if (fontMetrics.hasCapHeight()) {
2418 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2419 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2420
2421 // Make an adjustment to align with the cap height of a theoretical block line.
2422 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2423 logicalTopOffset += adjustment;
2424
2425 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2426 // positive for raised and negative for sunken).
2427 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2428
2429 // 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.
2430 if (dropHeightDelta < 0) {
2431 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2432 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2433 }
2434
2435 // 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
2436 // empty lines beside the first letter.
2437 if (dropHeightDelta > 0)
2438 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2439 }
2440 }
2441
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002442 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2443}
2444
2445bool RenderBlockFlow::positionNewFloats()
2446{
2447 if (!m_floatingObjects)
2448 return false;
2449
2450 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2451 if (floatingObjectSet.isEmpty())
2452 return false;
2453
2454 // If all floats have already been positioned, then we have no work to do.
2455 if (floatingObjectSet.last()->isPlaced())
2456 return false;
2457
2458 // Move backwards through our floating object list until we find a float that has
2459 // already been positioned. Then we'll be able to move forward, positioning all of
2460 // the new floats that need it.
2461 auto it = floatingObjectSet.end();
2462 --it; // Go to last item.
2463 auto begin = floatingObjectSet.begin();
2464 FloatingObject* lastPlacedFloatingObject = 0;
2465 while (it != begin) {
2466 --it;
2467 if ((*it)->isPlaced()) {
2468 lastPlacedFloatingObject = it->get();
2469 ++it;
2470 break;
2471 }
2472 }
2473
2474 LayoutUnit logicalTop = logicalHeight();
2475
2476 // The float cannot start above the top position of the last positioned float.
2477 if (lastPlacedFloatingObject)
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002478 logicalTop = std::max(logicalTopForFloat(*lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002479
2480 auto end = floatingObjectSet.end();
2481 // Now walk through the set of unpositioned floats and place them.
2482 for (; it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002483 auto& floatingObject = *it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002484 // The containing block is responsible for positioning floats, so if we have floats in our
2485 // list that come from somewhere else, do not attempt to position them.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002486 auto& childBox = floatingObject.renderer();
2487 if (childBox.containingBlock() != this)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002488 continue;
2489
akling@apple.com827be9c2013-10-29 02:58:43 +00002490 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002491
weinig@apple.com12840dc2013-10-22 23:59:08 +00002492 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002493
akling@apple.com827be9c2013-10-29 02:58:43 +00002494 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002495 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002496 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002497 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002498
2499 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2500
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002501 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002502
2503 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2504 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2505
2506 estimateRegionRangeForBoxChild(childBox);
2507
hyatt@apple.comccad3742015-02-04 21:39:00 +00002508 childBox.markForPaginationRelayoutIfNeeded();
2509 childBox.layoutIfNeeded();
2510
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002511 LayoutState* layoutState = view().layoutState();
2512 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002513 if (isPaginated) {
2514 // If we are unsplittable and don't fit, then we need to move down.
2515 // We include our margins as part of the unsplittable area.
2516 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2517
2518 // See if we have a pagination strut that is making us move down further.
2519 // Note that an unsplittable child can't also have a pagination strut, so this is
2520 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002521 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002522 if (childBlock && childBlock->paginationStrut()) {
2523 newLogicalTop += childBlock->paginationStrut();
2524 childBlock->setPaginationStrut(0);
2525 }
2526
2527 if (newLogicalTop != floatLogicalLocation.y()) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002528 floatingObject.setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002529
2530 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002531 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002532
2533 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2534 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2535
2536 if (childBlock)
2537 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002538 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002539 }
2540
2541 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002542 childBox.setNeedsLayout(MarkOnlyThis);
2543 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002544 }
2545 }
2546
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002547 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002548
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002549 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002550
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002551 m_floatingObjects->addPlacedObject(&floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002552
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002553#if ENABLE(CSS_SHAPES)
2554 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002555 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002556#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002557 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002558 if (childBox.checkForRepaintDuringLayout())
2559 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002560 }
2561 return true;
2562}
2563
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002564void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002565{
2566 positionNewFloats();
2567 // set y position
2568 LayoutUnit newY = 0;
2569 switch (clear) {
2570 case CLEFT:
2571 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2572 break;
2573 case CRIGHT:
2574 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2575 break;
2576 case CBOTH:
2577 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002578 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002579 default:
2580 break;
2581 }
2582 if (height() < newY)
2583 setLogicalHeight(newY);
2584}
2585
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002586LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002587{
2588 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002589 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002590
2591 return fixedOffset;
2592}
2593
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002594LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002595{
2596 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002597 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002598
2599 return fixedOffset;
2600}
2601
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002602LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002603{
2604 if (!m_floatingObjects)
2605 return logicalHeight;
2606
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002607 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2608}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002609
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002610LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2611{
2612 if (!m_floatingObjects)
2613 return logicalHeight;
2614
2615 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002616}
2617
2618LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2619{
2620 if (!m_floatingObjects)
2621 return 0;
2622 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002623 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2624 auto end = floatingObjectSet.end();
2625 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002626 const auto& floatingObject = *it->get();
2627 if (floatingObject.isPlaced() && floatingObject.type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002628 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002629 }
2630 return lowestFloatBottom;
2631}
2632
hyatt@apple.com87515262014-09-04 21:20:12 +00002633LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2634{
2635 if (!m_floatingObjects)
2636 return 0;
2637 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002638 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2639 auto end = floatingObjectSet.end();
2640 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002641 const auto& floatingObject = *it->get();
2642 if (floatingObject.isPlaced() && floatingObject.renderer().style().styleType() == FIRST_LETTER && floatingObject.renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002643 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002644 }
2645 return lowestFloatBottom;
2646}
2647
weinig@apple.com12840dc2013-10-22 23:59:08 +00002648LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002649{
2650 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002651 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002652 return 0;
2653
weinig@apple.com12840dc2013-10-22 23:59:08 +00002654 LayoutUnit childLogicalTop = child.logicalTop();
2655 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002656 LayoutUnit lowestFloatLogicalBottom = 0;
2657
2658 // Floats that will remain the child's responsibility to paint should factor into its
2659 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002660 auto childEnd = child.m_floatingObjects->set().end();
2661 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002662 auto& floatingObject = *childIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002663 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002664 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002665 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002666
2667 if (logicalBottom > logicalHeight()) {
2668 // If the object is not in the list, we add it now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002669 if (!containsFloat(floatingObject.renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002670 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2671 bool shouldPaint = false;
2672
2673 // The nearest enclosing layer always paints the float (so that zindex and stacking
2674 // behaves properly). We always want to propagate the desire to paint the float as
2675 // far out as we can, to the outermost block that overlaps the float, stopping only
2676 // if we hit a self-painting layer boundary.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002677 if (floatingObject.renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2678 floatingObject.setShouldPaint(false);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002679 shouldPaint = true;
2680 }
2681 // We create the floating object list lazily.
2682 if (!m_floatingObjects)
2683 createFloatingObjects();
2684
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002685 m_floatingObjects->add(floatingObject.copyToNewContainer(offset, shouldPaint, true));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002686 }
2687 } else {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002688 const auto& renderer = floatingObject.renderer();
2689 if (makeChildPaintOtherFloats && !floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()
2690 && renderer.isDescendantOf(&child) && renderer.enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002691 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2692 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2693 // layer.
2694 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2695 // it should paint.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002696 floatingObject.setShouldPaint(true);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002697 }
2698
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002699 // Since the float doesn't overhang, it didn't get put into our list. We need to add its overflow in to the child now.
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002700 if (floatingObject.isDescendant())
zalan@apple.com6816b132015-10-17 19:14:53 +00002701 child.addOverflowFromChild(&renderer, LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002702 }
2703 }
2704 return lowestFloatLogicalBottom;
2705}
2706
weinig@apple.com12840dc2013-10-22 23:59:08 +00002707bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002708{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002709 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002710 return false;
2711
2712 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002713 const auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002714 if (it == floatingObjectSet.end())
2715 return false;
2716
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002717 return logicalBottomForFloat(*it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002718}
2719
hyatt@apple.com21c60802015-04-01 18:10:32 +00002720void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002721{
2722 ASSERT(!avoidsFloats());
2723
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002724 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2725 if (createsNewFormattingContext())
2726 return;
2727
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002728 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2729 if (!prev->m_floatingObjects)
2730 return;
2731
2732 logicalLeftOffset += marginLogicalLeft();
2733
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002734 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2735 auto prevEnd = prevSet.end();
2736 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002737 auto& floatingObject = *prevIt->get();
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002738 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002739 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(floatingObject)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002740 // We create the floating object list lazily.
2741 if (!m_floatingObjects)
2742 createFloatingObjects();
2743
2744 // Applying the child's margin makes no sense in the case where the child was passed in.
2745 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2746 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2747 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2748 // will get applied twice.
2749 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002750 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2751 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002752
zalan@apple.com84ccfa12015-10-17 03:36:56 +00002753 m_floatingObjects->add(floatingObject.copyToNewContainer(offset));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002754 }
2755 }
2756 }
2757}
2758
2759void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2760{
2761 if (!everHadLayout() && !containsFloats())
2762 return;
2763
2764 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2765 setChildNeedsLayout(markParents);
2766
2767 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002768 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002769
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002770 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002771 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2772 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2773 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002774 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002775 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2776 block.setChildNeedsLayout(markParents);
2777 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002778 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002779 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002780 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2781 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002782 }
2783}
2784
2785void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2786{
2787 if (!m_floatingObjects)
2788 return;
2789
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002790 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2791 auto end = floatingObjectSet.end();
2792
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002793 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002794 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002795 continue;
2796
cdumez@apple.come9437792014-10-08 23:33:43 +00002797 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002798 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2799 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002800 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002801 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002802 if (nextBlock.containsFloat(floatingBox))
2803 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002804 }
2805 }
2806}
2807
zalan@apple.com6816b132015-10-17 19:14:53 +00002808LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject& child, const LayoutPoint& point) const
weinig@apple.com31324fd2013-10-28 19:22:51 +00002809{
akling@apple.com827be9c2013-10-29 02:58:43 +00002810 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002811 return point;
2812
2813 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2814 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2815 // case.
2816 if (isHorizontalWritingMode())
zalan@apple.com6816b132015-10-17 19:14:53 +00002817 return LayoutPoint(point.x(), point.y() + height() - child.renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2818 return LayoutPoint(point.x() + width() - child.renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
weinig@apple.com31324fd2013-10-28 19:22:51 +00002819}
2820
weinig@apple.com12840dc2013-10-22 23:59:08 +00002821LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002822{
2823 // There is no need to compute clearance if we have no floats.
2824 if (!containsFloats())
2825 return 0;
2826
2827 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002828 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002829 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002830 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002831 case CNONE:
2832 break;
2833 case CLEFT:
2834 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2835 break;
2836 case CRIGHT:
2837 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2838 break;
2839 case CBOTH:
2840 logicalBottom = lowestFloatLogicalBottom();
2841 break;
2842 }
2843
2844 // 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 +00002845 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002846 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002847 LayoutUnit newLogicalTop = logicalTop;
2848 while (true) {
2849 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2850 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2851 return newLogicalTop - logicalTop;
2852
2853 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002854 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002855 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2856
2857 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002858 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2859 LayoutUnit childOldMarginLeft = child.marginLeft();
2860 LayoutUnit childOldMarginRight = child.marginRight();
2861 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002862
weinig@apple.com12840dc2013-10-22 23:59:08 +00002863 child.setLogicalTop(newLogicalTop);
2864 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002865 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002866 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002867 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2868
weinig@apple.com12840dc2013-10-22 23:59:08 +00002869 child.setLogicalTop(childOldLogicalTop);
2870 child.setLogicalWidth(childOldLogicalWidth);
2871 child.setMarginLeft(childOldMarginLeft);
2872 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002873
2874 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2875 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2876 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2877 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2878 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002879 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002880 return newLogicalTop - logicalTop;
2881 }
2882
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002883 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002884 ASSERT(newLogicalTop >= logicalTop);
2885 if (newLogicalTop < logicalTop)
2886 break;
2887 }
2888 ASSERT_NOT_REACHED();
2889 }
2890 return result;
2891}
2892
2893bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2894{
2895 if (!m_floatingObjects)
2896 return false;
2897
2898 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002899 if (is<RenderView>(*this))
2900 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002901
2902 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2903 auto begin = floatingObjectSet.begin();
2904 for (auto it = floatingObjectSet.end(); it != begin;) {
2905 --it;
zalan@apple.com6816b132015-10-17 19:14:53 +00002906 const auto& floatingObject = *it->get();
2907 auto& renderer = floatingObject.renderer();
2908 if (floatingObject.shouldPaint() && !renderer.hasSelfPaintingLayer()) {
2909 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - renderer.x();
2910 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - renderer.y();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002911 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
zalan@apple.com6816b132015-10-17 19:14:53 +00002912 if (renderer.hitTest(request, result, locationInContainer, childPoint)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002913 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2914 return true;
2915 }
2916 }
2917 }
2918
2919 return false;
2920}
2921
weinig@apple.com611b9292013-10-20 22:57:54 +00002922bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2923{
2924 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002925
darin@apple.come1be6ca2014-04-28 04:19:10 +00002926 if (auto simpleLineLayout = this->simpleLineLayout())
2927 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002928
weinig@apple.com611b9292013-10-20 22:57:54 +00002929 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2930}
2931
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002932void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2933{
akling@apple.com827be9c2013-10-29 02:58:43 +00002934 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002935 return;
2936
2937 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2938 // for either overflow or translations via relative positioning.
2939 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002940 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2941
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00002942 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002943 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002944 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002945 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002946 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002947 }
2948 } else {
2949 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2950 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002951 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2952 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002953 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002954 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002955 left = std::min(left, x + obj->x());
2956 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002957 }
2958 }
2959 }
2960 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002961
2962 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002963 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2964 auto end = floatingObjectSet.end();
2965 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
zalan@apple.com6816b132015-10-17 19:14:53 +00002966 const auto& floatingObject = *it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002967 // Only examine the object if our m_shouldPaint flag is set.
zalan@apple.com6816b132015-10-17 19:14:53 +00002968 if (floatingObject.shouldPaint()) {
2969 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(floatingObject) - floatingObject.renderer().x();
2970 LayoutUnit floatRight = floatLeft + floatingObject.renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002971 left = std::min(left, floatLeft);
2972 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002973 }
2974 }
2975 }
2976}
2977
2978void RenderBlockFlow::fitBorderToLinesIfNeeded()
2979{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002980 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002981 return;
2982
2983 // Walk any normal flow lines to snugly fit.
2984 LayoutUnit left = LayoutUnit::max();
2985 LayoutUnit right = LayoutUnit::min();
2986 LayoutUnit oldWidth = contentWidth();
2987 adjustForBorderFit(0, left, right);
2988
2989 // Clamp to our existing edges. We can never grow. We only shrink.
2990 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2991 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002992 left = std::min(rightEdge, std::max(leftEdge, left));
2993 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002994
2995 LayoutUnit newContentWidth = right - left;
2996 if (newContentWidth == oldWidth)
2997 return;
2998
2999 setOverrideLogicalContentWidth(newContentWidth);
3000 layoutBlock(false);
3001 clearOverrideLogicalContentWidth();
3002}
3003
3004void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3005{
3006 if (logicalTop >= logicalBottom)
3007 return;
3008
antti@apple.combe9d3e12014-05-11 09:42:47 +00003009 // Floats currently affect the choice whether to use simple line layout path.
3010 if (m_simpleLineLayout) {
3011 invalidateLineLayoutPath();
3012 return;
3013 }
3014
weinig@apple.com611b9292013-10-20 22:57:54 +00003015 RootInlineBox* lowestDirtyLine = lastRootBox();
3016 RootInlineBox* afterLowest = lowestDirtyLine;
3017 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3018 afterLowest = lowestDirtyLine;
3019 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3020 }
3021
3022 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3023 afterLowest->markDirty();
3024 afterLowest = afterLowest->prevRootBox();
3025 }
3026}
3027
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003028Optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003029{
3030 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003031 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003032
3033 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003034 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003035
antti@apple.com940f5872013-10-24 20:31:11 +00003036 if (!hasLines())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003037 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003038
darin@apple.come1be6ca2014-04-28 04:19:10 +00003039 if (auto simpleLineLayout = this->simpleLineLayout())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003040 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003041
akling@apple.comee3c8df2013-11-06 08:09:44 +00003042 ASSERT(firstRootBox());
3043 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003044}
3045
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003046Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003047{
3048 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003049 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003050
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003051 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3052 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3053 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003054 if (!childrenInline()) {
3055 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3056 if (!inlineBlockBaseline)
3057 return inlineBlockBaseline;
3058 lastBaseline = inlineBlockBaseline.value();
3059 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003060 if (!hasLines()) {
3061 if (!hasLineIfEmpty())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003062 return Optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003063 const auto& fontMetrics = firstLineStyle().fontMetrics();
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003064 return Optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003065 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003066 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003067 }
3068
3069 if (auto simpleLineLayout = this->simpleLineLayout())
3070 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3071 else {
3072 bool isFirstLine = lastRootBox() == firstRootBox();
3073 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3074 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3075 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003076 }
3077 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3078 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3079 // enough with the spec to not cause tons of breakages).
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003080 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003081}
3082
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003083void RenderBlockFlow::setSelectionState(SelectionState state)
3084{
3085 if (state != SelectionNone)
3086 ensureLineBoxes();
3087 RenderBoxModelObject::setSelectionState(state);
3088}
3089
weinig@apple.com12840dc2013-10-22 23:59:08 +00003090GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003091 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3092{
antti@apple.comfea51992013-10-28 13:39:23 +00003093 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003094
weinig@apple.com611b9292013-10-20 22:57:54 +00003095 GapRects result;
3096
3097 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3098
antti@apple.com0e632aa2013-10-22 21:03:38 +00003099 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003100 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003101 // 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 +00003102 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3103 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3104 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3105 }
3106 return result;
3107 }
3108
3109 RootInlineBox* lastSelectedLine = 0;
3110 RootInlineBox* curr;
3111 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3112
3113 // Now paint the gaps for the lines.
3114 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3115 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3116 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3117
3118 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003119 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003120 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3121
3122 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3123 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003124 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003125 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3126 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3127 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3128
3129 lastSelectedLine = curr;
3130 }
3131
3132 if (containsStart && !lastSelectedLine)
3133 // VisibleSelection must start just after our last line.
3134 lastSelectedLine = lastRootBox();
3135
3136 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003137 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003138 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3139 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3140 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3141 }
3142 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003143}
3144
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003145void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3146{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003147 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003148 return;
3149
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003150 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3151 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003152 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003153 flowFragment->initializeStyle();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003154 setRenderNamedFlowFragment(flowFragment);
3155 addChild(renderNamedFlowFragment());
3156 }
3157}
3158
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003159bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3160{
3161 // A block without floats or that expands to enclose them won't need a relayout
3162 // after a region range change. There is no overflow content needing relayout
3163 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003164 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003165 return false;
3166
3167 return true;
3168}
3169
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003170bool RenderBlockFlow::canHaveChildren() const
3171{
3172 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3173}
3174
3175bool RenderBlockFlow::canHaveGeneratedChildren() const
3176{
3177 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3178}
3179
3180bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3181{
3182 if (!isRenderNamedFlowFragmentContainer())
3183 return false;
3184
3185 return hasRelativeLogicalHeight() && !isRenderView();
3186}
3187
3188void RenderBlockFlow::updateLogicalHeight()
3189{
3190 RenderBlock::updateLogicalHeight();
3191
abucur@adobe.comfad53712014-05-06 17:30:40 +00003192 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003193 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003194 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3195 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003196}
3197
3198void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3199{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003200 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003201 if (rareData.m_renderNamedFlowFragment)
3202 rareData.m_renderNamedFlowFragment->destroy();
3203 rareData.m_renderNamedFlowFragment = flowFragment;
3204}
3205
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003206void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3207{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003208 if (flowThread || hasRareBlockFlowData()) {
3209 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3210 rareData.m_multiColumnFlowThread = flowThread;
3211 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003212}
3213
akling@apple.com525dae62014-01-03 20:22:09 +00003214static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003215{
akling@apple.com38f0a652014-02-06 21:24:17 +00003216 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003217}
3218
3219RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3220{
3221 ASSERT(i >= 0);
3222
akling@apple.com827be9c2013-10-29 02:58:43 +00003223 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003224 return nullptr;
3225
3226 if (childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003227 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003228 if (!i--)
3229 return box;
3230 }
akling@apple.com525dae62014-01-03 20:22:09 +00003231 return nullptr;
3232 }
3233
3234 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3235 if (!shouldCheckLines(blockFlow))
3236 continue;
3237 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3238 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003239 }
3240
3241 return nullptr;
3242}
3243
3244int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3245{
akling@apple.com827be9c2013-10-29 02:58:43 +00003246 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003247 return 0;
3248
3249 int count = 0;
3250
3251 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003252 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003253 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003254 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003255 }
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003256 for (auto* box = firstRootBox(); box; box = box->nextRootBox()) {
3257 ++count;
weinig@apple.com17140912013-10-19 19:55:40 +00003258 if (box == stopRootInlineBox) {
3259 if (found)
3260 *found = true;
3261 break;
3262 }
3263 }
akling@apple.com525dae62014-01-03 20:22:09 +00003264 return count;
3265 }
3266
3267 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3268 if (!shouldCheckLines(blockFlow))
3269 continue;
3270 bool recursiveFound = false;
3271 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3272 if (recursiveFound) {
3273 if (found)
3274 *found = true;
3275 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003276 }
3277 }
3278
3279 return count;
3280}
3281
3282static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3283{
akling@apple.com827be9c2013-10-29 02:58:43 +00003284 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003285 return -1;
3286
3287 if (block.childrenInline()) {
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003288 for (auto* box = block.firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com17140912013-10-19 19:55:40 +00003289 if (++count == lineCount)
3290 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3291 }
3292 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003293 RenderBox* normalFlowChildWithoutLines = nullptr;
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003294 for (auto* obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003295 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3296 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003297 if (result != -1)
3298 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003299 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003300 normalFlowChildWithoutLines = obj;
3301 }
3302 if (normalFlowChildWithoutLines && !lineCount)
3303 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3304 }
3305
3306 return -1;
3307}
3308
3309int RenderBlockFlow::heightForLineCount(int lineCount)
3310{
3311 int count = 0;
3312 return getHeightForLineCount(*this, lineCount, true, count);
3313}
3314
3315void RenderBlockFlow::clearTruncation()
3316{
akling@apple.com827be9c2013-10-29 02:58:43 +00003317 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003318 return;
3319
3320 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003321 ensureLineBoxes();
3322
weinig@apple.com17140912013-10-19 19:55:40 +00003323 setHasMarkupTruncation(false);
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003324 for (auto* box = firstRootBox(); box; box = box->nextRootBox())
weinig@apple.com17140912013-10-19 19:55:40 +00003325 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003326 return;
3327 }
3328
3329 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3330 if (shouldCheckLines(blockFlow))
3331 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003332 }
3333}
3334
weinig@apple.com3f23b382013-10-19 20:26:58 +00003335bool RenderBlockFlow::containsNonZeroBidiLevel() const
3336{
cdumez@apple.comc1d54fa2015-10-13 19:15:55 +00003337 for (auto* root = firstRootBox(); root; root = root->nextRootBox()) {
3338 for (auto* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
weinig@apple.com3f23b382013-10-19 20:26:58 +00003339 if (box->bidiLevel())
3340 return true;
3341 }
3342 }
3343 return false;
3344}
3345
weinig@apple.com611b9292013-10-20 22:57:54 +00003346Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3347{
3348 if (!box)
3349 return Position();
3350
3351 if (!box->renderer().nonPseudoNode())
3352 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3353
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003354 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003355 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3356
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003357 auto& textBox = downcast<InlineTextBox>(*box);
3358 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003359}
3360
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003361VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003362{
3363 ASSERT(childrenInline());
3364
antti@apple.com940f5872013-10-24 20:31:11 +00003365 ensureLineBoxes();
3366
weinig@apple.com611b9292013-10-20 22:57:54 +00003367 if (!firstRootBox())
3368 return createVisiblePosition(0, DOWNSTREAM);
3369
akling@apple.com827be9c2013-10-29 02:58:43 +00003370 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3371 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003372
3373 // look for the closest line box in the root box which is at the passed-in y coordinate
3374 InlineBox* closestBox = 0;
3375 RootInlineBox* firstRootBoxWithChildren = 0;
3376 RootInlineBox* lastRootBoxWithChildren = 0;
3377 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003378 if (region && root->containingRegion() != region)
3379 continue;
3380
weinig@apple.com611b9292013-10-20 22:57:54 +00003381 if (!root->firstLeafChild())
3382 continue;
3383 if (!firstRootBoxWithChildren)
3384 firstRootBoxWithChildren = root;
3385
3386 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3387 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3388 break;
3389
3390 lastRootBoxWithChildren = root;
3391
3392 // check if this root line box is located at this y coordinate
3393 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3394 if (linesAreFlipped) {
3395 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3396 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3397 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3398
3399 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3400 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3401 continue;
3402 }
3403 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3404 if (closestBox)
3405 break;
3406 }
3407 }
3408
3409 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3410
3411 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3412 // y coordinate is below last root line box, pretend we hit it
3413 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3414 }
3415
3416 if (closestBox) {
3417 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003418 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003419 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3420 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3421 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3422 if (box->isLineBreak()) {
3423 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3424 box = newBox;
3425 }
3426 // y coordinate is above first root line box, so return the start of the first
3427 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3428 }
3429 }
3430
3431 // pass the box a top position that is inside it
3432 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3433 if (!isHorizontalWritingMode())
3434 point = point.transposedPoint();
3435 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003436 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003437 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003438 }
3439
3440 if (lastRootBoxWithChildren) {
3441 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3442 ASSERT(moveCaretToBoundary);
3443 InlineBox* logicallyLastBox;
3444 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3445 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3446 }
3447
3448 // Can't reach this. We have a root line box, but it has no kids.
3449 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3450 // seems to hit this code path.
3451 return createVisiblePosition(0, DOWNSTREAM);
3452}
3453
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003454VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003455{
3456 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003457 return fragment->positionForPoint(point, region);
3458 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003459}
3460
3461
weinig@apple.com611b9292013-10-20 22:57:54 +00003462void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3463{
antti@apple.com940f5872013-10-24 20:31:11 +00003464 ASSERT(childrenInline());
3465
3466 ensureLineBoxes();
3467
weinig@apple.com611b9292013-10-20 22:57:54 +00003468 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003469 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3470 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003471 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3472 if (!rect.isEmpty())
zalan@apple.com376339c2014-08-28 04:24:31 +00003473 rects.append(snappedIntRect(rect));
weinig@apple.com611b9292013-10-20 22:57:54 +00003474 }
3475}
3476
3477void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3478{
3479 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003480
darin@apple.come1be6ca2014-04-28 04:19:10 +00003481 if (auto simpleLineLayout = this->simpleLineLayout()) {
3482 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003483 return;
3484 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003485 m_lineBoxes.paint(this, paintInfo, paintOffset);
3486}
3487
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003488bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003489{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003490 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003491 return false;
3492
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003493 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003494 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3495
3496 bool needsRelayout;
3497 bool neededRelayout = false;
3498 bool firstPass = true;
3499 do {
3500 // Column heights may change here because of balancing. We may have to do multiple layout
3501 // passes, depending on how the contents is fitted to the changed column heights. In most
3502 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3503 // passes than that, though, but the number of retries should not exceed the number of
3504 // columns, unless we have a bug.
3505 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003506 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3507 if (multicolSet->recalculateColumnHeight(firstPass))
3508 needsRelayout = true;
3509 if (needsRelayout) {
3510 // Once a column set gets a new column height, that column set and all successive column
3511 // sets need to be laid out over again, since their logical top will be affected by
3512 // this, and therefore their column heights may change as well, at least if the multicol
3513 // height is constrained.
3514 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003515 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003516 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003517 if (needsRelayout) {
3518 // Layout again. Column balancing resulted in a new height.
3519 neededRelayout = true;
3520 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3521 setChildNeedsLayout(MarkOnlyThis);
3522 if (firstPass)
3523 statePusher.pop();
3524 layoutBlock(false);
3525 }
3526 firstPass = false;
3527 } while (needsRelayout);
3528
3529 multiColumnFlowThread()->setInBalancingPass(false);
3530
3531 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003532}
3533
antti@apple.com940f5872013-10-24 20:31:11 +00003534bool RenderBlockFlow::hasLines() const
3535{
3536 ASSERT(childrenInline());
3537
darin@apple.come1be6ca2014-04-28 04:19:10 +00003538 if (auto simpleLineLayout = this->simpleLineLayout())
3539 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003540
3541 return lineBoxes().firstLineBox();
3542}
3543
antti@apple.com9e891c82014-05-22 06:12:34 +00003544void RenderBlockFlow::invalidateLineLayoutPath()
3545{
akling@apple.coma12fee22015-02-01 02:58:13 +00003546 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003547 case UndeterminedPath:
3548 case ForceLineBoxesPath:
3549 ASSERT(!m_simpleLineLayout);
3550 return;
3551 case LineBoxesPath:
3552 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003553 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003554 return;
3555 case SimpleLinesPath:
3556 // The simple line layout may have become invalid.
3557 m_simpleLineLayout = nullptr;
3558 setNeedsLayout();
akling@apple.coma12fee22015-02-01 02:58:13 +00003559 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003560 return;
3561 }
3562 ASSERT_NOT_REACHED();
3563}
3564
zalan@apple.come37da962014-12-11 03:29:29 +00003565void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003566{
zalan@apple.come37da962014-12-11 03:29:29 +00003567 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3568 if (needsLayout) {
3569 deleteLineBoxesBeforeSimpleLineLayout();
3570 m_simpleLineLayout = SimpleLineLayout::create(*this);
3571 }
antti@apple.com940f5872013-10-24 20:31:11 +00003572 ASSERT(!m_lineBoxes.firstLineBox());
3573
antti@apple.comfea51992013-10-28 13:39:23 +00003574 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003575 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003576 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003577 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003578 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3579}
3580
3581void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3582{
akling@apple.coma12fee22015-02-01 02:58:13 +00003583 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003584 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003585 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3586 if (is<RenderText>(renderer))
3587 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3588 else if (is<RenderLineBreak>(renderer))
3589 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3590 else
3591 ASSERT_NOT_REACHED();
3592 }
antti@apple.com940f5872013-10-24 20:31:11 +00003593}
3594
3595void RenderBlockFlow::ensureLineBoxes()
3596{
akling@apple.coma12fee22015-02-01 02:58:13 +00003597 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003598 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003599 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003600 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003601
3602#if !ASSERT_DISABLED
3603 LayoutUnit oldHeight = logicalHeight();
3604#endif
3605 bool didNeedLayout = needsLayout();
3606
3607 bool relayoutChildren = false;
3608 LayoutUnit repaintLogicalTop;
3609 LayoutUnit repaintLogicalBottom;
3610 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3611
3612 updateLogicalHeight();
3613 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3614
3615 if (!didNeedLayout)
3616 clearNeedsLayout();
3617}
3618
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003619#if ENABLE(TREE_DEBUGGING)
zalan@apple.comfac337f2014-08-29 17:55:34 +00003620void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003621{
weinig@apple.com611b9292013-10-20 22:57:54 +00003622 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003623 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003624
3625 if (auto simpleLineLayout = this->simpleLineLayout())
3626 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003627}
3628#endif
3629
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003630RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3631{
3632 if (hasRareBlockFlowData())
3633 return *m_rareBlockFlowData;
3634 materializeRareBlockFlowData();
3635 return *m_rareBlockFlowData;
3636}
3637
3638void RenderBlockFlow::materializeRareBlockFlowData()
3639{
3640 ASSERT(!hasRareBlockFlowData());
3641 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3642}
3643
aestes@apple.com6751d842014-01-12 02:51:25 +00003644#if ENABLE(IOS_TEXT_AUTOSIZING)
3645inline static bool isVisibleRenderText(RenderObject* renderer)
3646{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003647 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003648 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003649 RenderText& renderText = downcast<RenderText>(*renderer);
3650 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003651}
3652
3653inline static bool resizeTextPermitted(RenderObject* render)
3654{
3655 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3656 auto renderer = render->parent();
3657 while (renderer) {
3658 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003659 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003660 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003661 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003662 }
3663 renderer = renderer->parent();
3664 }
3665 return true;
3666}
3667
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003668int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003669{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003670 if (style().visibility() != VISIBLE)
3671 return 0;
3672 if (childrenInline())
3673 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003674 // Only descend into list items.
3675 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003676 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3677 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003678 return count;
3679}
3680
3681static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3682{
3683 if (!render->isRenderBlock())
3684 return true;
3685 if (render->isListItem())
3686 return render->style().height().type() != Fixed;
3687 return false;
3688}
3689
3690// For now, we auto size single lines of text the same as multiple lines.
3691// We've been experimenting with low values for single lines of text.
3692static inline float oneLineTextMultiplier(float specifiedSize)
3693{
3694 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3695}
3696
3697static inline float textMultiplier(float specifiedSize)
3698{
3699 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3700}
3701
3702void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3703{
3704 // Don't do any work if the block is smaller than the visible area.
3705 if (visibleWidth >= width())
3706 return;
3707
3708 unsigned lineCount;
3709 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003710 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003711 if (!count)
3712 lineCount = NO_LINE;
3713 else if (count == 1)
3714 lineCount = ONE_LINE;
3715 else
3716 lineCount = MULTI_LINE;
3717 } else
3718 lineCount = m_lineCountForTextAutosizing;
3719
3720 ASSERT(lineCount != NOT_SET);
3721 if (lineCount == NO_LINE)
3722 return;
3723
3724 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3725 float scale = visibleWidth / actualWidth;
3726 float minFontSize = roundf(size / scale);
3727
3728 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3729 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003730 RenderText& text = downcast<RenderText>(*descendent);
3731 RenderStyle& oldStyle = text.style();
antti@apple.com214b7162015-09-16 00:16:58 +00003732 auto fontDescription = oldStyle.fontDescription();
aestes@apple.com6751d842014-01-12 02:51:25 +00003733 float specifiedSize = fontDescription.specifiedSize();
3734 float scaledSize = roundf(specifiedSize * scale);
3735 if (scaledSize > 0 && scaledSize < minFontSize) {
3736 // 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.
3737 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3738 if (m_lineCountForTextAutosizing == NOT_SET)
3739 m_lineCountForTextAutosizing = lineCount;
3740 if (m_widthForTextAutosizing == -1)
3741 m_widthForTextAutosizing = actualWidth;
3742
3743 float candidateNewSize = 0;
3744 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3745 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003746 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3747 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003748 }
3749 }
3750 }
3751}
3752#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3753
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003754RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3755{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003756 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3757 if (!flowThread)
3758 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003759
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003760 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003761
3762 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003763 flowThread->setChildNeedsLayout(MarkOnlyThis);
3764
3765 if (flowThread->needsLayout()) {
3766 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3767 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3768
zalan@apple.com9ac63c42016-01-14 20:09:51 +00003769 flowThread->invalidateRegions(MarkOnlyThis);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003770 flowThread->setNeedsHeightsRecalculation(true);
3771 flowThread->layout();
3772 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003773 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3774 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3775 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3776 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3777 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3778 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3779 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3780 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003781 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003782 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003783 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003784
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003785 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003786}
3787
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003788void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3789{
3790 if (multiColumnFlowThread())
3791 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003792 if (beforeChild) {
3793 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3794 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3795 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003796 RenderBlock::addChild(newChild, beforeChild);
3797}
3798
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003799void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003800{
3801 if (!documentBeingDestroyed()) {
3802 RenderFlowThread* flowThread = multiColumnFlowThread();
3803 if (flowThread && flowThread != &oldChild)
3804 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3805 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003806 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003807}
3808
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003809void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003810{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003811 // If we don't use columns or flow threads, then bail.
3812 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003813 return;
3814
3815 // 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 +00003816 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3817 LogicalExtentComputedValues computedValues;
3818 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3819 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003820 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003821 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003822 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3823 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003824 } else if (is<RenderFlowThread>(*this)) {
3825 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003826
3827 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3828 // is known. The page logical height thing in LayoutState is meaningless for flow
3829 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3830 // thread), but as long as it is used universally as a means to determine whether page
3831 // height is known or not, we need this. Page height is unknown when column balancing is
3832 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3833 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3834 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3835 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003836 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003837
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003838 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003839 }
3840}
3841
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003842bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3843{
3844 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3845 // in the RenderView instead.
simon.fraser@apple.comf63871d2015-10-10 02:20:52 +00003846 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isDocumentElementRenderer() || isBody());
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003847
3848 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3849}
3850
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003851void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3852{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003853 bool destroyColumns = !requiresColumns(count);
3854 if (destroyColumns) {
3855 if (multiColumnFlowThread())
3856 destroyMultiColumnFlowThread();
3857 } else {
3858 if (!multiColumnFlowThread())
3859 createMultiColumnFlowThread();
3860 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003861 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3862 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003863 }
3864}
3865
cdumez@apple.com78141732014-11-04 23:00:48 +00003866void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003867{
hyatt@apple.com86919862014-01-27 16:27:45 +00003868 if (!multiColumnFlowThread())
3869 return;
3870
3871 bool needsLayout = false;
3872 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003873 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003874 if (oldProgressionIsInline != newProgressionIsInline) {
3875 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3876 needsLayout = true;
3877 }
3878
3879 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003880 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003881 if (oldProgressionIsReversed != newProgressionIsReversed) {
3882 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3883 needsLayout = true;
3884 }
3885
3886 if (needsLayout)
3887 setNeedsLayoutAndPrefWidthsRecalc();
3888}
3889
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003890LayoutUnit RenderBlockFlow::computedColumnWidth() const
3891{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003892 if (multiColumnFlowThread())
3893 return multiColumnFlowThread()->computedColumnWidth();
3894 return contentLogicalWidth();
3895}
3896
3897unsigned RenderBlockFlow::computedColumnCount() const
3898{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003899 if (multiColumnFlowThread())
3900 return multiColumnFlowThread()->computedColumnCount();
3901
3902 return 1;
3903}
3904
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003905bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3906{
3907 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3908 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3909 return hasTopOverflow;
3910
3911 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3912 hasTopOverflow = !hasTopOverflow;
3913
3914 return hasTopOverflow;
3915}
3916
3917bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3918{
3919 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3920 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3921 return hasLeftOverflow;
3922
3923 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3924 hasLeftOverflow = !hasLeftOverflow;
3925
3926 return hasLeftOverflow;
3927}
3928
zalan@apple.comac6956c2014-09-05 14:18:06 +00003929struct InlineMinMaxIterator {
3930/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3931 inline min/max width calculations. Note the following about the way it walks:
3932 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3933 (2) We do not drill into the children of floats or replaced elements, since you can't break
3934 in the middle of such an element.
3935 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3936 distinct borders/margin/padding that contribute to the min/max width.
3937*/
3938 const RenderBlockFlow& parent;
3939 RenderObject* current;
3940 bool endOfInline;
3941 bool initial;
3942
3943 InlineMinMaxIterator(const RenderBlockFlow& p)
3944 : parent(p)
3945 , current(nullptr)
3946 , endOfInline(false)
3947 , initial(true)
3948 { }
3949
3950 RenderObject* next();
3951};
3952
3953RenderObject* InlineMinMaxIterator::next()
3954{
3955 RenderObject* result = nullptr;
3956 bool oldEndOfInline = endOfInline;
3957 endOfInline = false;
3958 do {
3959 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3960 result = current->firstChildSlow();
3961 else if (initial) {
3962 result = parent.firstChild();
3963 initial = false;
3964 }
3965
3966 if (!result) {
3967 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3968 if (!oldEndOfInline && current && current->isRenderInline()) {
3969 result = current;
3970 endOfInline = true;
3971 break;
3972 }
3973
3974 while (current && current != &parent) {
3975 result = current->nextSibling();
3976 if (result)
3977 break;
3978 current = current->parent();
3979 if (current && current != &parent && current->isRenderInline()) {
3980 result = current;
3981 endOfInline = true;
3982 break;
3983 }
3984 }
3985 }
3986
3987 if (!result)
3988 break;
3989
3990 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3991 break;
3992
3993 current = result;
3994 result = nullptr;
3995 } while (current || current == &parent);
3996 // Update our position.
3997 current = result;
3998 return result;
3999}
4000
4001static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4002{
4003 if (cssUnit.type() != Auto)
4004 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4005 return 0;
4006}
4007
4008static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4009{
4010 const RenderStyle& childStyle = child.style();
4011 if (endOfInline) {
4012 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4013 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4014 child.borderEnd();
4015 }
4016 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4017 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4018 child.borderStart();
4019}
4020
4021static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4022{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004023 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004024 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004025 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004026 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004027 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004028 float spaceWidth = font.width(RenderBlock::constructTextRun(&renderText, font, &space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004029 inlineMax -= spaceWidth + font.wordSpacing();
4030 if (inlineMin > inlineMax)
4031 inlineMin = inlineMax;
4032 }
4033}
4034
4035static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4036{
4037 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4038}
4039
4040void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4041{
4042 float inlineMax = 0;
4043 float inlineMin = 0;
4044
4045 const RenderStyle& styleToUse = style();
4046 RenderBlock* containingBlock = this->containingBlock();
4047 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4048
4049 // If we are at the start of a line, we want to ignore all white-space.
4050 // Also strip spaces if we previously had text that ended in a trailing space.
4051 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004052 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004053
4054 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4055 // very specific cirucumstances (in order to match common WinIE renderings).
4056 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4057 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4058
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004059 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004060
4061 InlineMinMaxIterator childIterator(*this);
4062
4063 // Only gets added to the max preffered width once.
4064 bool addedTextIndent = false;
4065 // Signals the text indent was more negative than the min preferred width
4066 bool hasRemainingNegativeTextIndent = false;
4067
4068 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4069 RenderObject* prevFloat = 0;
4070 bool isPrevChildInlineFlow = false;
4071 bool shouldBreakLineAfterText = false;
4072 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004073 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004074 child->style().autoWrap();
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004075 bool isAnonymousInlineBlock = child->isAnonymousInlineBlock();
4076
zalan@apple.comac6956c2014-09-05 14:18:06 +00004077 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004078 // Step One: determine whether or not we need to terminate our current line.
4079 // Each discrete chunk can become the new min-width, if it is the widest chunk
4080 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004081
4082 // Children fall into three categories:
4083 // (1) An inline flow object. These objects always have a min/max of 0,
4084 // and are included in the iteration solely so that their margins can
4085 // be added in.
4086 //
4087 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4088 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004089 // we need to break the current line, and then add in our own margins and min/max
4090 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004091 //
4092 // (3) A text object. Text runs can have breakable characters at the start,
4093 // the middle or the end. They may also lose whitespace off the front if
4094 // we're already ignoring whitespace. In order to compute accurate min-width
4095 // information, we need three pieces of information.
4096 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4097 // starts with whitespace.
4098 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4099 // ends with whitespace.
4100 // (c) the min/max width of the string (trimmed for whitespace).
4101 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004102 // If the text string starts with whitespace, then we need to terminate our current line
4103 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004104 //
4105 // If the text string has a breakable character in the middle, but didn't start
4106 // with whitespace, then we add the width of the first non-breakable run and
4107 // then end the current line. We then need to use the intermediate min/max width
4108 // values (if any of them are larger than our current min/max). We then look at
4109 // the width of the last non-breakable run and use that to start a new line
4110 // (unless we end in whitespace).
4111 const RenderStyle& childStyle = child->style();
4112 float childMin = 0;
4113 float childMax = 0;
4114
4115 if (!child->isText()) {
4116 if (child->isLineBreakOpportunity()) {
4117 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4118 inlineMin = 0;
4119 continue;
4120 }
4121 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004122 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004123 // Add in padding/border/margin from the appropriate side of
4124 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004125 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004126 childMin += bpm;
4127 childMax += bpm;
4128
4129 inlineMin += childMin;
4130 inlineMax += childMax;
4131
4132 child->setPreferredLogicalWidthsDirty(false);
4133 } else {
4134 // Inline replaced elts add in their margins to their min/max values.
4135 LayoutUnit margins = 0;
4136 Length startMargin = childStyle.marginStart();
4137 Length endMargin = childStyle.marginEnd();
4138 if (startMargin.isFixed())
4139 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4140 if (endMargin.isFixed())
4141 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4142 childMin += margins.ceilToFloat();
4143 childMax += margins.ceilToFloat();
4144 }
4145 }
4146
cdumez@apple.comf8022152014-10-15 00:29:51 +00004147 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004148 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004149 // Terminate the current line as far as minwidth is concerned.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004150 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4151 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4152
4153 bool clearPreviousFloat;
4154 if (child->isFloating()) {
4155 clearPreviousFloat = (prevFloat
4156 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4157 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4158 prevFloat = child;
4159 } else
4160 clearPreviousFloat = false;
4161
4162 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004163 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) || isAnonymousInlineBlock) {
4164 if (child->isAnonymousInlineBlock() && styleToUse.collapseWhiteSpace())
4165 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004166 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4167 inlineMin = 0;
4168 }
4169
4170 // If we're supposed to clear the previous float, then terminate maxwidth as well.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004171 if (clearPreviousFloat || isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004172 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4173 inlineMax = 0;
4174 }
4175
4176 // Add in text-indent. This is added in only once.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004177 if (!addedTextIndent && !child->isFloating() && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004178 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4179 childMin += ceiledIndent;
4180 childMax += ceiledIndent;
4181
4182 if (childMin < 0)
4183 textIndent = LayoutUnit::fromFloatCeil(childMin);
4184 else
4185 addedTextIndent = true;
4186 }
4187
4188 // Add our width to the max.
4189 inlineMax += std::max<float>(0, childMax);
4190
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004191 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004192 if (child->isFloating())
4193 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4194 else
4195 inlineMin += childMin;
4196 } else {
4197 // Now check our line.
4198 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4199
4200 // Now start a new line.
4201 inlineMin = 0;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004202
4203 if (child->isAnonymousInlineBlock()) {
4204 // Terminate max width as well.
4205 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4206 inlineMax = 0;
4207 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004208 }
4209
4210 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4211 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4212 inlineMin = 0;
4213 }
4214
4215 // We are no longer stripping whitespace at the start of a line.
4216 if (!child->isFloating()) {
4217 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004218 trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004219 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004220 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004221 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004222 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004223
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004224 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4225 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004226
4227 // Determine if we have a breakable character. Pass in
4228 // whether or not we should ignore any spaces at the front
4229 // of the string. If those are going to be stripped out,
4230 // then they shouldn't be considered in the breakable char
4231 // check.
4232 bool hasBreakableChar, hasBreak;
4233 float beginMin, endMin;
4234 bool beginWS, endWS;
4235 float beginMax, endMax;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004236 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004237 hasBreakableChar, hasBreak, beginMax, endMax,
4238 childMin, childMax, stripFrontSpaces);
4239
4240 // This text object will not be rendered, but it may still provide a breaking opportunity.
4241 if (!hasBreak && !childMax) {
4242 if (autoWrap && (beginWS || endWS)) {
4243 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4244 inlineMin = 0;
4245 }
4246 continue;
4247 }
4248
4249 if (stripFrontSpaces)
4250 trailingSpaceChild = child;
4251 else
4252 trailingSpaceChild = 0;
4253
4254 // Add in text-indent. This is added in only once.
4255 float ti = 0;
4256 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4257 ti = textIndent.ceilToFloat();
4258 childMin += ti;
4259 beginMin += ti;
4260
4261 // It the text indent negative and larger than the child minimum, we re-use the remainder
4262 // in future minimum calculations, but using the negative value again on the maximum
4263 // will lead to under-counting the max pref width.
4264 if (!addedTextIndent) {
4265 childMax += ti;
4266 beginMax += ti;
4267 addedTextIndent = true;
4268 }
4269
4270 if (childMin < 0) {
4271 textIndent = childMin;
4272 hasRemainingNegativeTextIndent = true;
4273 }
4274 }
4275
4276 // If we have no breakable characters at all,
4277 // then this is the easy case. We add ourselves to the current
4278 // min and max and continue.
4279 if (!hasBreakableChar)
4280 inlineMin += childMin;
4281 else {
4282 // We have a breakable character. Now we need to know if
4283 // we start and end with whitespace.
4284 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004285 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004286 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4287 } else {
4288 inlineMin += beginMin;
4289 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4290 childMin -= ti;
4291 }
4292
4293 inlineMin = childMin;
4294
4295 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004296 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004297 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4298 inlineMin = 0;
4299 shouldBreakLineAfterText = false;
4300 } else {
4301 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4302 inlineMin = endMin;
4303 shouldBreakLineAfterText = true;
4304 }
4305 }
4306
4307 if (hasBreak) {
4308 inlineMax += beginMax;
4309 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4310 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4311 inlineMax = endMax;
4312 addedTextIndent = true;
4313 } else
4314 inlineMax += std::max<float>(0, childMax);
4315 }
4316
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004317 // Ignore spaces after a list marker and also after an anonymous inline block.
4318 if (child->isListMarker() || isAnonymousInlineBlock)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004319 stripFrontSpaces = true;
4320 } else {
4321 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4322 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4323 inlineMin = inlineMax = 0;
4324 stripFrontSpaces = true;
4325 trailingSpaceChild = 0;
4326 addedTextIndent = true;
4327 }
4328
4329 if (!child->isText() && child->isRenderInline())
4330 isPrevChildInlineFlow = true;
4331 else
4332 isPrevChildInlineFlow = false;
4333
4334 oldAutoWrap = autoWrap;
4335 }
4336
4337 if (styleToUse.collapseWhiteSpace())
4338 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4339
4340 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4341 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4342}
4343
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004344}
4345// namespace WebCore