blob: 9a1d2698fc085bbfcdab011afc07f50f19608be2 [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)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +000098 : RenderBlock(element, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +000099#if ENABLE(IOS_TEXT_AUTOSIZING)
100 , m_widthForTextAutosizing(-1)
101 , m_lineCountForTextAutosizing(NOT_SET)
102#endif
hyatt@apple.com5388e672013-09-06 20:54:47 +0000103{
weinig@apple.com611b9292013-10-20 22:57:54 +0000104 setChildrenInline(true);
akling@apple.com42e10632013-10-14 17:55:52 +0000105}
106
akling@apple.com689f7612014-12-14 08:21:05 +0000107RenderBlockFlow::RenderBlockFlow(Document& document, Ref<RenderStyle>&& style)
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +0000108 : RenderBlock(document, WTF::move(style), RenderBlockFlowFlag)
aestes@apple.com6751d842014-01-12 02:51:25 +0000109#if ENABLE(IOS_TEXT_AUTOSIZING)
110 , m_widthForTextAutosizing(-1)
111 , m_lineCountForTextAutosizing(NOT_SET)
112#endif
akling@apple.com42e10632013-10-14 17:55:52 +0000113{
weinig@apple.com611b9292013-10-20 22:57:54 +0000114 setChildrenInline(true);
hyatt@apple.com5388e672013-09-06 20:54:47 +0000115}
116
117RenderBlockFlow::~RenderBlockFlow()
118{
119}
120
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000121void RenderBlockFlow::createMultiColumnFlowThread()
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000122{
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000123 RenderMultiColumnFlowThread* flowThread = new RenderMultiColumnFlowThread(document(), RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK));
124 flowThread->initializeStyle();
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000125 setChildrenInline(false); // Do this to avoid wrapping inline children that are just going to move into the flow thread.
abucur@adobe.com99757c62014-07-31 13:43:52 +0000126 deleteLines();
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000127 RenderBlock::addChild(flowThread);
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000128 flowThread->populate(); // Called after the flow thread is inserted so that we are reachable by the flow thread.
hyatt@apple.comd4be3772014-01-24 19:55:33 +0000129 setMultiColumnFlowThread(flowThread);
130}
131
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000132void RenderBlockFlow::destroyMultiColumnFlowThread()
133{
hyatt@apple.comc1c39032014-04-15 23:25:58 +0000134 multiColumnFlowThread()->evacuateAndDestroy();
135 ASSERT(!multiColumnFlowThread());
hyatt@apple.com39746fd2014-01-24 22:52:41 +0000136}
137
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000138void RenderBlockFlow::insertedIntoTree()
139{
140 RenderBlock::insertedIntoTree();
141 createRenderNamedFlowFragmentIfNeeded();
142}
143
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000144void RenderBlockFlow::willBeDestroyed()
145{
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000146 if (renderNamedFlowFragment())
147 setRenderNamedFlowFragment(0);
weinig@apple.com611b9292013-10-20 22:57:54 +0000148
weinig@apple.com611b9292013-10-20 22:57:54 +0000149 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
150 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
151 destroyLeftoverChildren();
152
weinig@apple.com611b9292013-10-20 22:57:54 +0000153 if (!documentBeingDestroyed()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000154 if (firstRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000155 // We can't wait for RenderBox::destroy to clear the selection,
156 // because by then we will have nuked the line boxes.
weinig@apple.com611b9292013-10-20 22:57:54 +0000157 if (isSelectionBorder())
zalan@apple.come36543a2014-07-29 01:45:54 +0000158 frame().selection().setNeedsSelectionUpdate();
weinig@apple.com611b9292013-10-20 22:57:54 +0000159
160 // If we are an anonymous block, then our line boxes might have children
161 // that will outlast this block. In the non-anonymous block case those
162 // children will be destroyed by the time we return from this function.
163 if (isAnonymousBlock()) {
akling@apple.comee3c8df2013-11-06 08:09:44 +0000164 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
weinig@apple.com611b9292013-10-20 22:57:54 +0000165 while (auto childBox = box->firstChild())
166 childBox->removeFromParent();
167 }
168 }
akling@apple.coma1986f52014-12-08 22:17:55 +0000169 } else if (parent())
170 parent()->dirtyLinesFromChangedChild(*this);
weinig@apple.com611b9292013-10-20 22:57:54 +0000171 }
172
akling@apple.com31dd4f42013-10-30 22:27:59 +0000173 m_lineBoxes.deleteLineBoxes();
weinig@apple.com611b9292013-10-20 22:57:54 +0000174
dbates@webkit.org34f59002014-05-20 20:34:35 +0000175 removeFromUpdateScrollInfoAfterLayoutTransaction();
weinig@apple.com611b9292013-10-20 22:57:54 +0000176
177 // NOTE: This jumps down to RenderBox, bypassing RenderBlock since it would do duplicate work.
178 RenderBox::willBeDestroyed();
hyatt@apple.com3cd5c772013-09-27 18:22:50 +0000179}
180
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000181RenderBlockFlow* RenderBlockFlow::previousSiblingWithOverhangingFloats(bool& parentHasFloats) const
182{
183 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
184 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
185 // to avoid floats.
186 parentHasFloats = false;
187 for (RenderObject* sibling = previousSibling(); sibling; sibling = sibling->previousSibling()) {
188 if (is<RenderBlockFlow>(*sibling)) {
189 auto& siblingBlock = downcast<RenderBlockFlow>(*sibling);
190 if (!siblingBlock.avoidsFloats())
191 return &siblingBlock;
192 }
193 if (sibling->isFloating())
194 parentHasFloats = true;
195 }
196 return nullptr;
197}
198
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +0000199void RenderBlockFlow::rebuildFloatingObjectSetFromIntrudingFloats()
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000200{
201 if (m_floatingObjects)
202 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
203
204 HashSet<RenderBox*> oldIntrudingFloatSet;
205 if (!childrenInline() && m_floatingObjects) {
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.
216 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
mihnea@adobe.combe79cf12013-10-17 09:02:19 +0000217 if (m_floatingObjects)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000218 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000219 if (!oldIntrudingFloatSet.isEmpty())
220 markAllDescendantsWithFloatsForLayout();
221 return;
222 }
223
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000224 RendererToFloatInfoMap floatMap;
225
226 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000227 if (childrenInline())
228 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
229 else
230 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000231 }
232
233 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
234 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
235 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000236 bool isBlockInsideInline = isAnonymousInlineBlock();
237 if (!is<RenderBlockFlow>(parent()) && !isBlockInsideInline)
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000238 return;
239
robert@webkit.org97037ef2013-11-20 19:26:10 +0000240 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into
241 // them (as opposed to floats they contain themselves) so check for those here too.
hyatt@apple.com21c60802015-04-01 18:10:32 +0000242 RenderBlockFlow& parentBlock = downcast<RenderBlockFlow>(isBlockInsideInline ? *containingBlock() : *parent());
243 bool parentHasFloats = isBlockInsideInline ? parentBlock.containsFloats() : false;
244 RenderBlockFlow* previousBlock = nullptr;
245 if (!isBlockInsideInline)
246 previousBlock = previousSiblingWithOverhangingFloats(parentHasFloats);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000247 LayoutUnit logicalTopOffset = logicalTop();
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000248 if (parentHasFloats || (parentBlock.lowestFloatLogicalBottom() > logicalTopOffset && previousBlock && previousBlock->isSelfCollapsingBlock()))
hyatt@apple.com21c60802015-04-01 18:10:32 +0000249 addIntrudingFloats(&parentBlock, &parentBlock, parentBlock.logicalLeftOffsetForContent(), logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000250
251 LayoutUnit logicalLeftOffset = 0;
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000252 if (previousBlock)
253 logicalTopOffset -= previousBlock->logicalTop();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000254 else {
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000255 previousBlock = &parentBlock;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +0000256 logicalLeftOffset += parentBlock.logicalLeftOffsetForContent();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000257 }
258
259 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
jfernandez@igalia.com93f23d22014-12-09 17:44:40 +0000260 if (previousBlock->m_floatingObjects && previousBlock->lowestFloatLogicalBottom() > logicalTopOffset)
hyatt@apple.com21c60802015-04-01 18:10:32 +0000261 addIntrudingFloats(previousBlock, &parentBlock, logicalLeftOffset, logicalTopOffset);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000262
263 if (childrenInline()) {
264 LayoutUnit changeLogicalTop = LayoutUnit::max();
265 LayoutUnit changeLogicalBottom = LayoutUnit::min();
266 if (m_floatingObjects) {
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) {
270 FloatingObject* floatingObject = it->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000271 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) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000274 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000275 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000276 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000277 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000278 } else {
279 if (logicalBottom != oldLogicalBottom) {
andersca@apple.com86298632013-11-10 19:32:33 +0000280 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom));
281 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000282 }
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000283 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000284 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000285 if (logicalTop != oldLogicalTop) {
andersca@apple.com86298632013-11-10 19:32:33 +0000286 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop));
287 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000288 }
289 }
290
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000291 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
292 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
293 oldFloatingObject->originatingLine()->markDirty();
294 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000295 } else {
296 changeLogicalTop = 0;
andersca@apple.com86298632013-11-10 19:32:33 +0000297 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000298 }
299 }
300 }
301
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +0000302 auto end = floatMap.end();
303 for (auto it = floatMap.begin(); it != end; ++it) {
304 FloatingObject* floatingObject = it->value.get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000305 if (!floatingObject->isDescendant()) {
306 changeLogicalTop = 0;
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
524 layoutPositionedObjects(relayoutChildren || isRoot());
525
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000526 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
527 computeOverflow(oldClientAfterEdge);
528
529 statePusher.pop();
530
531 fitBorderToLinesIfNeeded();
532
533 if (view().layoutState()->m_pageLogicalHeight)
534 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
535
536 updateLayerTransform();
537
538 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
539 // we overflow or not.
540 updateScrollInfoAfterLayout();
541
542 // FIXME: This repaint logic should be moved into a separate helper function!
543 // Repaint with our new bounds if they are different from our old bounds.
544 bool didFullRepaint = repainter.repaintAfterLayout();
akling@apple.com827be9c2013-10-29 02:58:43 +0000545 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse.visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000546 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
547 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
548 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
549 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
550 if (hasOverflowClip()) {
551 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
552 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
553 // layoutInlineChildren should be patched to compute the entire repaint rect.
andersca@apple.com86298632013-11-10 19:32:33 +0000554 repaintLogicalLeft = std::min(repaintLogicalLeft, logicalLeftLayoutOverflow());
555 repaintLogicalRight = std::max(repaintLogicalRight, logicalRightLayoutOverflow());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000556 }
557
558 LayoutRect repaintRect;
559 if (isHorizontalWritingMode())
560 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
561 else
562 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
563
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
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00001983 setLineGridBox(WTF::move(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{
2041 for (auto child = firstChildBox(); child && (child->isInFlowRenderFlowThread() || child->isRenderMultiColumnSet()); child = child->nextSiblingBox())
2042 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) {
2130 FloatingObject* r = it->get();
2131 if (r->isDescendant())
2132 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
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) {
2157 FloatingObject* 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.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002161 if (logicalBottomForFloat(floatingObject) > logicalHeight()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002162 && !floatingObject->renderer().hasSelfPaintingLayer()
2163 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
2164 floatingObject->renderer().repaint();
2165 floatingObject->renderer().repaintOverhangingFloats(false);
2166 }
2167 }
2168}
2169
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002170void RenderBlockFlow::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& point)
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002171{
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002172 RenderBlock::paintColumnRules(paintInfo, point);
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002173
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002174 if (!multiColumnFlowThread() || paintInfo.context().paintingDisabled())
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002175 return;
hyatt@apple.comc9021b72014-04-25 21:05:59 +00002176
hyatt@apple.com58b5ecc2014-04-17 23:06:02 +00002177 // Iterate over our children and paint the column rules as needed.
2178 for (auto& columnSet : childrenOfType<RenderMultiColumnSet>(*this)) {
2179 LayoutPoint childPoint = columnSet.location() + flipForWritingModeForChild(&columnSet, point);
2180 columnSet.paintColumnRules(paintInfo, childPoint);
2181 }
2182}
2183
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002184void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
2185{
2186 if (!m_floatingObjects)
2187 return;
2188
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002189 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2190 auto end = floatingObjectSet.end();
2191 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2192 FloatingObject* r = it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002193 // Only paint the object if our m_shouldPaint flag is set.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002194 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002195 PaintInfo currentPaintInfo(paintInfo);
2196 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2197 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002198 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
2199 r->renderer().paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002200 if (!preservePhase) {
2201 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002202 r->renderer().paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002203 currentPaintInfo.phase = PaintPhaseFloat;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002204 r->renderer().paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002205 currentPaintInfo.phase = PaintPhaseForeground;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002206 r->renderer().paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002207 currentPaintInfo.phase = PaintPhaseOutline;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002208 r->renderer().paint(currentPaintInfo, childPoint);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002209 }
2210 }
2211 }
2212}
2213
weinig@apple.com12840dc2013-10-22 23:59:08 +00002214void RenderBlockFlow::clipOutFloatingObjects(RenderBlock& rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002215{
2216 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002217 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2218 auto end = floatingObjectSet.end();
2219 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2220 FloatingObject* floatingObject = it->get();
2221 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
2222 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002223 floatingObject->renderer().width(), floatingObject->renderer().height());
weinig@apple.com12840dc2013-10-22 23:59:08 +00002224 rootBlock.flipForWritingMode(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002225 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
mmaxfield@apple.coma93d7ef2015-08-29 06:15:28 +00002226 paintInfo->context().clipOut(snappedIntRect(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002227 }
2228 }
2229}
2230
2231void RenderBlockFlow::createFloatingObjects()
2232{
zandobersek@gmail.com31dae992014-03-31 10:12:49 +00002233 m_floatingObjects = std::make_unique<FloatingObjects>(*this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002234}
2235
2236void RenderBlockFlow::removeFloatingObjects()
2237{
2238 if (!m_floatingObjects)
2239 return;
2240
bjonesbe@adobe.com0b2195a2014-04-11 22:46:02 +00002241 markSiblingsWithFloatsForLayout();
2242
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002243 m_floatingObjects->clear();
2244}
2245
weinig@apple.com12840dc2013-10-22 23:59:08 +00002246FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002247{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002248 ASSERT(floatBox.isFloating());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002249
2250 // Create the list of special objects if we don't aleady have one
2251 if (!m_floatingObjects)
2252 createFloatingObjects();
2253 else {
2254 // Don't insert the floatingObject again if it's already in the list
2255 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002256 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002257 if (it != floatingObjectSet.end())
2258 return it->get();
2259 }
2260
2261 // Create the special floatingObject entry & append it to the list
2262
weinig@apple.com12840dc2013-10-22 23:59:08 +00002263 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002264
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002265 // 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 +00002266 bool isChildRenderBlock = floatBox.isRenderBlock();
2267 if (isChildRenderBlock && !floatBox.needsLayout() && view().layoutState()->pageLogicalHeightChanged())
2268 floatBox.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002269
2270 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002271 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) {
2272 // We are unsplittable if we're a block flow root.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002273 floatBox.layoutIfNeeded();
bjonesbe@adobe.com9c29e692014-12-10 00:57:10 +00002274 floatingObject->setShouldPaint(!floatBox.hasSelfPaintingLayer());
2275 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002276 else {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002277 floatBox.updateLogicalWidth();
2278 floatBox.computeAndSetBlockDirectionMargins(this);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002279 }
2280
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002281 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002282
dbates@webkit.org0cefe4f2014-07-03 22:13:54 +00002283 return m_floatingObjects->add(WTF::move(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002284}
2285
weinig@apple.com12840dc2013-10-22 23:59:08 +00002286void RenderBlockFlow::removeFloatingObject(RenderBox& floatBox)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002287{
2288 if (m_floatingObjects) {
2289 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002290 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002291 if (it != floatingObjectSet.end()) {
2292 FloatingObject* floatingObject = it->get();
2293 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002294 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
2295 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002296
2297 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
2298 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
2299 logicalBottom = LayoutUnit::max();
2300 else {
2301 // Special-case zero- and less-than-zero-height floats: those don't touch
2302 // the line that they're on, but it still needs to be dirtied. This is
2303 // accomplished by pretending they have a height of 1.
andersca@apple.com86298632013-11-10 19:32:33 +00002304 logicalBottom = std::max(logicalBottom, logicalTop + 1);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002305 }
2306 if (floatingObject->originatingLine()) {
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002307 floatingObject->originatingLine()->removeFloat(floatBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002308 if (!selfNeedsLayout()) {
2309 ASSERT(&floatingObject->originatingLine()->renderer() == this);
2310 floatingObject->originatingLine()->markDirty();
2311 }
2312#if !ASSERT_DISABLED
2313 floatingObject->setOriginatingLine(0);
2314#endif
2315 }
2316 markLinesDirtyInBlockRange(0, logicalBottom);
2317 }
2318 m_floatingObjects->remove(floatingObject);
2319 }
2320 }
2321}
2322
2323void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
2324{
2325 if (!containsFloats())
2326 return;
2327
2328 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2329 FloatingObject* curr = floatingObjectSet.last().get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002330 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002331 m_floatingObjects->remove(curr);
2332 if (floatingObjectSet.isEmpty())
2333 break;
2334 curr = floatingObjectSet.last().get();
2335 }
2336}
2337
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002338LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2339{
2340 LayoutUnit offset = fixedOffset;
2341 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2342 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2343 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent);
2344}
2345
2346LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const
2347{
2348 LayoutUnit offset = fixedOffset;
2349 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2350 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining);
2351 return adjustLogicalRightOffsetForLine(offset, applyTextIndent);
2352}
2353
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002354LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002355{
weinig@apple.com12840dc2013-10-22 23:59:08 +00002356 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002357 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
zoltan@webkit.org7d4f8cc2014-03-26 18:20:15 +00002358 LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002359
andersca@apple.com86298632013-11-10 19:32:33 +00002360 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002361
2362 LayoutUnit floatLogicalLeft;
2363
2364 bool insideFlowThread = flowThreadContainingBlock();
hyatt@apple.com87515262014-09-04 21:20:12 +00002365 bool isInitialLetter = childBox.style().styleType() == FIRST_LETTER && childBox.style().initialLetterDrop() > 0;
2366
2367 if (isInitialLetter) {
2368 int letterClearance = lowestInitialLetterLogicalBottom() - logicalTopOffset;
2369 if (letterClearance > 0) {
2370 logicalTopOffset += letterClearance;
2371 setLogicalHeight(logicalHeight() + letterClearance);
2372 }
2373 }
2374
akling@apple.com827be9c2013-10-29 02:58:43 +00002375 if (childBox.style().floating() == LeftFloat) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002376 LayoutUnit heightRemainingLeft = 1;
2377 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002378 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
2379 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002380 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002381 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002382 if (insideFlowThread) {
2383 // Have to re-evaluate all of our offsets, since they may have changed.
2384 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2385 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002386 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002387 }
2388 }
andersca@apple.com86298632013-11-10 19:32:33 +00002389 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002390 } else {
2391 LayoutUnit heightRemainingLeft = 1;
2392 LayoutUnit heightRemainingRight = 1;
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002393 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
2394 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
andersca@apple.com86298632013-11-10 19:32:33 +00002395 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight);
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002396 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002397 if (insideFlowThread) {
2398 // Have to re-evaluate all of our offsets, since they may have changed.
2399 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
2400 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
andersca@apple.com86298632013-11-10 19:32:33 +00002401 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002402 }
2403 }
2404 // Use the original width of the float here, since the local variable
2405 // |floatLogicalWidth| was capped to the available line width. See
2406 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002407 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002408 }
2409
hyatt@apple.com87515262014-09-04 21:20:12 +00002410 if (isInitialLetter) {
hyatt@apple.comc2e15522014-09-03 19:26:38 +00002411 const RenderStyle& style = firstLineStyle();
2412 const FontMetrics& fontMetrics = style.fontMetrics();
2413 if (fontMetrics.hasCapHeight()) {
2414 LayoutUnit heightOfLine = lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
2415 LayoutUnit beforeMarginBorderPadding = childBox.borderAndPaddingBefore() + childBox.marginBefore();
2416
2417 // Make an adjustment to align with the cap height of a theoretical block line.
2418 LayoutUnit adjustment = fontMetrics.ascent() + (heightOfLine - fontMetrics.height()) / 2 - fontMetrics.capHeight() - beforeMarginBorderPadding;
2419 logicalTopOffset += adjustment;
2420
2421 // For sunken and raised caps, we have to make some adjustments. Test if we're sunken or raised (dropHeightDelta will be
2422 // positive for raised and negative for sunken).
2423 int dropHeightDelta = childBox.style().initialLetterHeight() - childBox.style().initialLetterDrop();
2424
2425 // 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.
2426 if (dropHeightDelta < 0) {
2427 LayoutUnit marginTopIncrease = -dropHeightDelta * heightOfLine;
2428 childBox.setMarginBefore(childBox.marginTop() + marginTopIncrease);
2429 }
2430
2431 // 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
2432 // empty lines beside the first letter.
2433 if (dropHeightDelta > 0)
2434 setLogicalHeight(logicalHeight() + dropHeightDelta * heightOfLine);
2435 }
2436 }
2437
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002438 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
2439}
2440
2441bool RenderBlockFlow::positionNewFloats()
2442{
2443 if (!m_floatingObjects)
2444 return false;
2445
2446 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2447 if (floatingObjectSet.isEmpty())
2448 return false;
2449
2450 // If all floats have already been positioned, then we have no work to do.
2451 if (floatingObjectSet.last()->isPlaced())
2452 return false;
2453
2454 // Move backwards through our floating object list until we find a float that has
2455 // already been positioned. Then we'll be able to move forward, positioning all of
2456 // the new floats that need it.
2457 auto it = floatingObjectSet.end();
2458 --it; // Go to last item.
2459 auto begin = floatingObjectSet.begin();
2460 FloatingObject* lastPlacedFloatingObject = 0;
2461 while (it != begin) {
2462 --it;
2463 if ((*it)->isPlaced()) {
2464 lastPlacedFloatingObject = it->get();
2465 ++it;
2466 break;
2467 }
2468 }
2469
2470 LayoutUnit logicalTop = logicalHeight();
2471
2472 // The float cannot start above the top position of the last positioned float.
2473 if (lastPlacedFloatingObject)
andersca@apple.com86298632013-11-10 19:32:33 +00002474 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002475
2476 auto end = floatingObjectSet.end();
2477 // Now walk through the set of unpositioned floats and place them.
2478 for (; it != end; ++it) {
2479 FloatingObject* floatingObject = it->get();
2480 // The containing block is responsible for positioning floats, so if we have floats in our
2481 // list that come from somewhere else, do not attempt to position them.
2482 if (floatingObject->renderer().containingBlock() != this)
2483 continue;
2484
weinig@apple.com12840dc2013-10-22 23:59:08 +00002485 RenderBox& childBox = floatingObject->renderer();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002486
akling@apple.com827be9c2013-10-29 02:58:43 +00002487 LayoutUnit childLogicalLeftMargin = style().isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002488
weinig@apple.com12840dc2013-10-22 23:59:08 +00002489 LayoutRect oldRect = childBox.frameRect();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002490
akling@apple.com827be9c2013-10-29 02:58:43 +00002491 if (childBox.style().clear() & CLEFT)
andersca@apple.com86298632013-11-10 19:32:33 +00002492 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
akling@apple.com827be9c2013-10-29 02:58:43 +00002493 if (childBox.style().clear() & CRIGHT)
andersca@apple.com86298632013-11-10 19:32:33 +00002494 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002495
2496 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
2497
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002498 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002499
2500 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2501 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2502
2503 estimateRegionRangeForBoxChild(childBox);
2504
hyatt@apple.comccad3742015-02-04 21:39:00 +00002505 childBox.markForPaginationRelayoutIfNeeded();
2506 childBox.layoutIfNeeded();
2507
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002508 LayoutState* layoutState = view().layoutState();
2509 bool isPaginated = layoutState->isPaginated();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002510 if (isPaginated) {
2511 // If we are unsplittable and don't fit, then we need to move down.
2512 // We include our margins as part of the unsplittable area.
2513 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
2514
2515 // See if we have a pagination strut that is making us move down further.
2516 // Note that an unsplittable child can't also have a pagination strut, so this is
2517 // exclusive with the case above.
cdumez@apple.come9437792014-10-08 23:33:43 +00002518 RenderBlock* childBlock = is<RenderBlock>(childBox) ? &downcast<RenderBlock>(childBox) : nullptr;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002519 if (childBlock && childBlock->paginationStrut()) {
2520 newLogicalTop += childBlock->paginationStrut();
2521 childBlock->setPaginationStrut(0);
2522 }
2523
2524 if (newLogicalTop != floatLogicalLocation.y()) {
2525 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
2526
2527 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002528 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002529
2530 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
2531 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
2532
2533 if (childBlock)
2534 childBlock->setChildNeedsLayout(MarkOnlyThis);
weinig@apple.com12840dc2013-10-22 23:59:08 +00002535 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002536 }
2537
2538 if (updateRegionRangeForBoxChild(childBox)) {
weinig@apple.com12840dc2013-10-22 23:59:08 +00002539 childBox.setNeedsLayout(MarkOnlyThis);
2540 childBox.layoutIfNeeded();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002541 }
2542 }
2543
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002544 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002545
stavila@adobe.comb0d86c42014-04-09 17:07:50 +00002546 setLogicalHeightForFloat(floatingObject, logicalHeightForChildForFragmentation(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002547
2548 m_floatingObjects->addPlacedObject(floatingObject);
2549
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002550#if ENABLE(CSS_SHAPES)
2551 if (ShapeOutsideInfo* shapeOutside = childBox.shapeOutsideInfo())
bjonesbe@adobe.com029f74e2014-02-13 03:02:53 +00002552 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox));
zoltan@webkit.org0faf5722013-11-05 02:34:16 +00002553#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002554 // If the child moved, we have to repaint it.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002555 if (childBox.checkForRepaintDuringLayout())
2556 childBox.repaintDuringLayoutIfMoved(oldRect);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002557 }
2558 return true;
2559}
2560
bjonesbe@adobe.comf9f10402014-02-20 19:40:28 +00002561void RenderBlockFlow::clearFloats(EClear clear)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002562{
2563 positionNewFloats();
2564 // set y position
2565 LayoutUnit newY = 0;
2566 switch (clear) {
2567 case CLEFT:
2568 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2569 break;
2570 case CRIGHT:
2571 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2572 break;
2573 case CBOTH:
2574 newY = lowestFloatLogicalBottom();
joepeck@webkit.orgaa676ee52014-01-28 04:04:52 +00002575 break;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002576 default:
2577 break;
2578 }
2579 if (height() < newY)
2580 setLogicalHeight(newY);
2581}
2582
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002583LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002584{
2585 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002586 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002587
2588 return fixedOffset;
2589}
2590
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002591LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002592{
2593 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
bjonesbe@adobe.com98b899b2013-11-07 18:11:43 +00002594 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002595
2596 return fixedOffset;
2597}
2598
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002599LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002600{
2601 if (!m_floatingObjects)
2602 return logicalHeight;
2603
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002604 return m_floatingObjects->findNextFloatLogicalBottomBelow(logicalHeight);
2605}
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002606
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002607LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelowForBlock(LayoutUnit logicalHeight) const
2608{
2609 if (!m_floatingObjects)
2610 return logicalHeight;
2611
2612 return m_floatingObjects->findNextFloatLogicalBottomBelowForBlock(logicalHeight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002613}
2614
2615LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2616{
2617 if (!m_floatingObjects)
2618 return 0;
2619 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002620 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2621 auto end = floatingObjectSet.end();
2622 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2623 FloatingObject* floatingObject = it->get();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002624 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002625 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002626 }
2627 return lowestFloatBottom;
2628}
2629
hyatt@apple.com87515262014-09-04 21:20:12 +00002630LayoutUnit RenderBlockFlow::lowestInitialLetterLogicalBottom() const
2631{
2632 if (!m_floatingObjects)
2633 return 0;
2634 LayoutUnit lowestFloatBottom = 0;
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002635 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2636 auto end = floatingObjectSet.end();
2637 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2638 FloatingObject* floatingObject = it->get();
hyatt@apple.com87515262014-09-04 21:20:12 +00002639 if (floatingObject->isPlaced() && floatingObject->renderer().style().styleType() == FIRST_LETTER && floatingObject->renderer().style().initialLetterDrop() > 0)
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002640 lowestFloatBottom = std::max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.com87515262014-09-04 21:20:12 +00002641 }
2642 return lowestFloatBottom;
2643}
2644
weinig@apple.com12840dc2013-10-22 23:59:08 +00002645LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow& child, bool makeChildPaintOtherFloats)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002646{
2647 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00002648 if (!child.containsFloats() || child.createsNewFormattingContext())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002649 return 0;
2650
weinig@apple.com12840dc2013-10-22 23:59:08 +00002651 LayoutUnit childLogicalTop = child.logicalTop();
2652 LayoutUnit childLogicalLeft = child.logicalLeft();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002653 LayoutUnit lowestFloatLogicalBottom = 0;
2654
2655 // Floats that will remain the child's responsibility to paint should factor into its
2656 // overflow.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002657 auto childEnd = child.m_floatingObjects->set().end();
2658 for (auto childIt = child.m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
2659 FloatingObject* floatingObject = childIt->get();
2660 LayoutUnit floatLogicalBottom = std::min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002661 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
andersca@apple.com86298632013-11-10 19:32:33 +00002662 lowestFloatLogicalBottom = std::max(lowestFloatLogicalBottom, logicalBottom);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002663
2664 if (logicalBottom > logicalHeight()) {
2665 // If the object is not in the list, we add it now.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002666 if (!containsFloat(floatingObject->renderer())) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002667 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2668 bool shouldPaint = false;
2669
2670 // The nearest enclosing layer always paints the float (so that zindex and stacking
2671 // behaves properly). We always want to propagate the desire to paint the float as
2672 // far out as we can, to the outermost block that overlaps the float, stopping only
2673 // if we hit a self-painting layer boundary.
2674 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2675 floatingObject->setShouldPaint(false);
2676 shouldPaint = true;
2677 }
2678 // We create the floating object list lazily.
2679 if (!m_floatingObjects)
2680 createFloatingObjects();
2681
2682 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2683 }
2684 } else {
2685 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
weinig@apple.com12840dc2013-10-22 23:59:08 +00002686 && floatingObject->renderer().isDescendantOf(&child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child.enclosingFloatPaintingLayer()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002687 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2688 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2689 // layer.
2690 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2691 // it should paint.
2692 floatingObject->setShouldPaint(true);
2693 }
2694
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00002695 // Since the float doesn't overhang, it didn't get put into our list. We need to add its overflow in to the child now.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002696 if (floatingObject->isDescendant())
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002697 child.addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002698 }
2699 }
2700 return lowestFloatLogicalBottom;
2701}
2702
weinig@apple.com12840dc2013-10-22 23:59:08 +00002703bool RenderBlockFlow::hasOverhangingFloat(RenderBox& renderer)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002704{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00002705 if (!m_floatingObjects || !parent())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002706 return false;
2707
2708 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002709 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(renderer);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002710 if (it == floatingObjectSet.end())
2711 return false;
2712
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002713 return logicalBottomForFloat(it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002714}
2715
hyatt@apple.com21c60802015-04-01 18:10:32 +00002716void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, RenderBlockFlow* container, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002717{
2718 ASSERT(!avoidsFloats());
2719
jfernandez@igalia.com70658682014-12-15 21:07:30 +00002720 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent.
2721 if (createsNewFormattingContext())
2722 return;
2723
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002724 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2725 if (!prev->m_floatingObjects)
2726 return;
2727
2728 logicalLeftOffset += marginLogicalLeft();
2729
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002730 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2731 auto prevEnd = prevSet.end();
2732 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2733 FloatingObject* floatingObject = prevIt->get();
2734 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002735 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2736 // We create the floating object list lazily.
2737 if (!m_floatingObjects)
2738 createFloatingObjects();
2739
2740 // Applying the child's margin makes no sense in the case where the child was passed in.
2741 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2742 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2743 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2744 // will get applied twice.
2745 LayoutSize offset = isHorizontalWritingMode()
hyatt@apple.com21c60802015-04-01 18:10:32 +00002746 ? LayoutSize(logicalLeftOffset - (prev != container ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2747 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != container ? prev->marginTop() : LayoutUnit()));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002748
2749 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2750 }
2751 }
2752 }
2753}
2754
2755void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2756{
2757 if (!everHadLayout() && !containsFloats())
2758 return;
2759
2760 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2761 setChildNeedsLayout(markParents);
2762
2763 if (floatToRemove)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002764 removeFloatingObject(*floatToRemove);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002765
zalan@apple.com5d7ffdf2014-10-29 21:13:12 +00002766 // Iterate over our block children and mark them as needed.
akling@apple.com525dae62014-01-03 20:22:09 +00002767 for (auto& block : childrenOfType<RenderBlock>(*this)) {
2768 if (!floatToRemove && block.isFloatingOrOutOfFlowPositioned())
2769 continue;
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002770 if (!is<RenderBlockFlow>(block)) {
akling@apple.com525dae62014-01-03 20:22:09 +00002771 if (block.shrinkToAvoidFloats() && block.everHadLayout())
2772 block.setChildNeedsLayout(markParents);
2773 continue;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002774 }
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002775 auto& blockFlow = downcast<RenderBlockFlow>(block);
akling@apple.com525dae62014-01-03 20:22:09 +00002776 if ((floatToRemove ? blockFlow.containsFloat(*floatToRemove) : blockFlow.containsFloats()) || blockFlow.shrinkToAvoidFloats())
2777 blockFlow.markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002778 }
2779}
2780
2781void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2782{
2783 if (!m_floatingObjects)
2784 return;
2785
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002786 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2787 auto end = floatingObjectSet.end();
2788
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002789 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
zalan@apple.comc2472ea2015-05-26 22:59:40 +00002790 if (!is<RenderBlockFlow>(*next) || next->isFloatingOrOutOfFlowPositioned())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002791 continue;
2792
cdumez@apple.come9437792014-10-08 23:33:43 +00002793 RenderBlockFlow& nextBlock = downcast<RenderBlockFlow>(*next);
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002794 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2795 RenderBox& floatingBox = (*it)->renderer();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002796 if (floatToRemove && &floatingBox != floatToRemove)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002797 continue;
cdumez@apple.come9437792014-10-08 23:33:43 +00002798 if (nextBlock.containsFloat(floatingBox))
2799 nextBlock.markAllDescendantsWithFloatsForLayout(&floatingBox);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002800 }
2801 }
2802}
2803
weinig@apple.com31324fd2013-10-28 19:22:51 +00002804LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
2805{
akling@apple.com827be9c2013-10-29 02:58:43 +00002806 if (!style().isFlippedBlocksWritingMode())
weinig@apple.com31324fd2013-10-28 19:22:51 +00002807 return point;
2808
2809 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
2810 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2811 // case.
2812 if (isHorizontalWritingMode())
2813 return LayoutPoint(point.x(), point.y() + height() - child->renderer().height() - 2 * yPositionForFloatIncludingMargin(child));
2814 return LayoutPoint(point.x() + width() - child->renderer().width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2815}
2816
weinig@apple.com12840dc2013-10-22 23:59:08 +00002817LayoutUnit RenderBlockFlow::getClearDelta(RenderBox& child, LayoutUnit logicalTop)
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002818{
2819 // There is no need to compute clearance if we have no floats.
2820 if (!containsFloats())
2821 return 0;
2822
2823 // At least one float is present. We need to perform the clearance computation.
akling@apple.com827be9c2013-10-29 02:58:43 +00002824 bool clearSet = child.style().clear() != CNONE;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002825 LayoutUnit logicalBottom = 0;
akling@apple.com827be9c2013-10-29 02:58:43 +00002826 switch (child.style().clear()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002827 case CNONE:
2828 break;
2829 case CLEFT:
2830 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2831 break;
2832 case CRIGHT:
2833 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2834 break;
2835 case CBOTH:
2836 logicalBottom = lowestFloatLogicalBottom();
2837 break;
2838 }
2839
2840 // 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 +00002841 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
weinig@apple.com12840dc2013-10-22 23:59:08 +00002842 if (!result && child.avoidsFloats()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002843 LayoutUnit newLogicalTop = logicalTop;
2844 while (true) {
2845 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2846 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2847 return newLogicalTop - logicalTop;
2848
2849 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002850 LayoutRect borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002851 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2852
2853 // FIXME: None of this is right for perpendicular writing-mode children.
weinig@apple.com12840dc2013-10-22 23:59:08 +00002854 LayoutUnit childOldLogicalWidth = child.logicalWidth();
2855 LayoutUnit childOldMarginLeft = child.marginLeft();
2856 LayoutUnit childOldMarginRight = child.marginRight();
2857 LayoutUnit childOldLogicalTop = child.logicalTop();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002858
weinig@apple.com12840dc2013-10-22 23:59:08 +00002859 child.setLogicalTop(newLogicalTop);
2860 child.updateLogicalWidth();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002861 region = regionAtBlockOffset(logicalTopForChild(child));
weinig@apple.com12840dc2013-10-22 23:59:08 +00002862 borderBox = child.borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002863 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2864
weinig@apple.com12840dc2013-10-22 23:59:08 +00002865 child.setLogicalTop(childOldLogicalTop);
2866 child.setLogicalWidth(childOldLogicalWidth);
2867 child.setMarginLeft(childOldMarginLeft);
2868 child.setMarginRight(childOldMarginRight);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002869
2870 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2871 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2872 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2873 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2874 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
weinig@apple.com12840dc2013-10-22 23:59:08 +00002875 child.setChildNeedsLayout(MarkOnlyThis);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002876 return newLogicalTop - logicalTop;
2877 }
2878
bjonesbe@adobe.comedea3422013-11-08 22:01:33 +00002879 newLogicalTop = nextFloatLogicalBottomBelowForBlock(newLogicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002880 ASSERT(newLogicalTop >= logicalTop);
2881 if (newLogicalTop < logicalTop)
2882 break;
2883 }
2884 ASSERT_NOT_REACHED();
2885 }
2886 return result;
2887}
2888
2889bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2890{
2891 if (!m_floatingObjects)
2892 return false;
2893
2894 LayoutPoint adjustedLocation = accumulatedOffset;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00002895 if (is<RenderView>(*this))
2896 adjustedLocation += toLayoutSize(downcast<RenderView>(*this).frameView().scrollPosition());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002897
2898 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2899 auto begin = floatingObjectSet.begin();
2900 for (auto it = floatingObjectSet.end(); it != begin;) {
2901 --it;
2902 FloatingObject* floatingObject = it->get();
2903 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2904 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2905 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2906 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2907 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2908 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2909 return true;
2910 }
2911 }
2912 }
2913
2914 return false;
2915}
2916
weinig@apple.com611b9292013-10-20 22:57:54 +00002917bool RenderBlockFlow::hitTestInlineChildren(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
2918{
2919 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00002920
darin@apple.come1be6ca2014-04-28 04:19:10 +00002921 if (auto simpleLineLayout = this->simpleLineLayout())
2922 return SimpleLineLayout::hitTestFlow(*this, *simpleLineLayout, request, result, locationInContainer, accumulatedOffset, hitTestAction);
antti@apple.com940f5872013-10-24 20:31:11 +00002923
weinig@apple.com611b9292013-10-20 22:57:54 +00002924 return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
2925}
2926
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002927void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2928{
akling@apple.com827be9c2013-10-29 02:58:43 +00002929 if (style().visibility() != VISIBLE)
weinig@apple.com611b9292013-10-20 22:57:54 +00002930 return;
2931
2932 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
2933 // for either overflow or translations via relative positioning.
2934 if (childrenInline()) {
antti@apple.com940f5872013-10-24 20:31:11 +00002935 const_cast<RenderBlockFlow&>(*this).ensureLineBoxes();
2936
weinig@apple.com611b9292013-10-20 22:57:54 +00002937 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
2938 if (box->firstChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002939 left = std::min(left, x + LayoutUnit(box->firstChild()->x()));
weinig@apple.com611b9292013-10-20 22:57:54 +00002940 if (box->lastChild())
zalan@apple.com390064f2014-02-26 06:23:03 +00002941 right = std::max(right, x + LayoutUnit(ceilf(box->lastChild()->logicalRight())));
weinig@apple.com611b9292013-10-20 22:57:54 +00002942 }
2943 } else {
2944 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2945 if (!obj->isFloatingOrOutOfFlowPositioned()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00002946 if (is<RenderBlockFlow>(*obj) && !obj->hasOverflowClip())
2947 downcast<RenderBlockFlow>(*obj).adjustForBorderFit(x + obj->x(), left, right);
akling@apple.com827be9c2013-10-29 02:58:43 +00002948 else if (obj->style().visibility() == VISIBLE) {
weinig@apple.com611b9292013-10-20 22:57:54 +00002949 // We are a replaced element or some kind of non-block-flow object.
andersca@apple.com86298632013-11-10 19:32:33 +00002950 left = std::min(left, x + obj->x());
2951 right = std::max(right, x + obj->x() + obj->width());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002952 }
2953 }
2954 }
2955 }
weinig@apple.com611b9292013-10-20 22:57:54 +00002956
2957 if (m_floatingObjects) {
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002958 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2959 auto end = floatingObjectSet.end();
2960 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2961 FloatingObject* r = it->get();
weinig@apple.com611b9292013-10-20 22:57:54 +00002962 // Only examine the object if our m_shouldPaint flag is set.
commit-queue@webkit.org6ad70c22015-06-12 18:43:01 +00002963 if (r->shouldPaint()) {
2964 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2965 LayoutUnit floatRight = floatLeft + r->renderer().width();
andersca@apple.com86298632013-11-10 19:32:33 +00002966 left = std::min(left, floatLeft);
2967 right = std::max(right, floatRight);
weinig@apple.com611b9292013-10-20 22:57:54 +00002968 }
2969 }
2970 }
2971}
2972
2973void RenderBlockFlow::fitBorderToLinesIfNeeded()
2974{
rego@igalia.comf7d624c2015-04-22 10:31:24 +00002975 if (style().borderFit() == BorderFitBorder || hasOverrideLogicalContentWidth())
weinig@apple.com611b9292013-10-20 22:57:54 +00002976 return;
2977
2978 // Walk any normal flow lines to snugly fit.
2979 LayoutUnit left = LayoutUnit::max();
2980 LayoutUnit right = LayoutUnit::min();
2981 LayoutUnit oldWidth = contentWidth();
2982 adjustForBorderFit(0, left, right);
2983
2984 // Clamp to our existing edges. We can never grow. We only shrink.
2985 LayoutUnit leftEdge = borderLeft() + paddingLeft();
2986 LayoutUnit rightEdge = leftEdge + oldWidth;
andersca@apple.com86298632013-11-10 19:32:33 +00002987 left = std::min(rightEdge, std::max(leftEdge, left));
2988 right = std::max(leftEdge, std::min(rightEdge, right));
weinig@apple.com611b9292013-10-20 22:57:54 +00002989
2990 LayoutUnit newContentWidth = right - left;
2991 if (newContentWidth == oldWidth)
2992 return;
2993
2994 setOverrideLogicalContentWidth(newContentWidth);
2995 layoutBlock(false);
2996 clearOverrideLogicalContentWidth();
2997}
2998
2999void RenderBlockFlow::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3000{
3001 if (logicalTop >= logicalBottom)
3002 return;
3003
antti@apple.combe9d3e12014-05-11 09:42:47 +00003004 // Floats currently affect the choice whether to use simple line layout path.
3005 if (m_simpleLineLayout) {
3006 invalidateLineLayoutPath();
3007 return;
3008 }
3009
weinig@apple.com611b9292013-10-20 22:57:54 +00003010 RootInlineBox* lowestDirtyLine = lastRootBox();
3011 RootInlineBox* afterLowest = lowestDirtyLine;
3012 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3013 afterLowest = lowestDirtyLine;
3014 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3015 }
3016
3017 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3018 afterLowest->markDirty();
3019 afterLowest = afterLowest->prevRootBox();
3020 }
3021}
3022
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003023Optional<int> RenderBlockFlow::firstLineBaseline() const
weinig@apple.com611b9292013-10-20 22:57:54 +00003024{
3025 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003026 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003027
3028 if (!childrenInline())
antti@apple.com0e632aa2013-10-22 21:03:38 +00003029 return RenderBlock::firstLineBaseline();
weinig@apple.com611b9292013-10-20 22:57:54 +00003030
antti@apple.com940f5872013-10-24 20:31:11 +00003031 if (!hasLines())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003032 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003033
darin@apple.come1be6ca2014-04-28 04:19:10 +00003034 if (auto simpleLineLayout = this->simpleLineLayout())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003035 return Optional<int>(SimpleLineLayout::computeFlowFirstLineBaseline(*this, *simpleLineLayout));
antti@apple.com940f5872013-10-24 20:31:11 +00003036
akling@apple.comee3c8df2013-11-06 08:09:44 +00003037 ASSERT(firstRootBox());
3038 return firstRootBox()->logicalTop() + firstLineStyle().fontMetrics().ascent(firstRootBox()->baselineType());
weinig@apple.com611b9292013-10-20 22:57:54 +00003039}
3040
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003041Optional<int> RenderBlockFlow::inlineBlockBaseline(LineDirectionMode lineDirection) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003042{
3043 if (isWritingModeRoot() && !isRubyRun())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003044 return Optional<int>();
weinig@apple.com611b9292013-10-20 22:57:54 +00003045
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003046 // Note that here we only take the left and bottom into consideration. Our caller takes the right and top into consideration.
3047 float boxHeight = lineDirection == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
3048 float lastBaseline;
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003049 if (!childrenInline()) {
3050 Optional<int> inlineBlockBaseline = RenderBlock::inlineBlockBaseline(lineDirection);
3051 if (!inlineBlockBaseline)
3052 return inlineBlockBaseline;
3053 lastBaseline = inlineBlockBaseline.value();
3054 } else {
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003055 if (!hasLines()) {
3056 if (!hasLineIfEmpty())
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003057 return Optional<int>();
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003058 const auto& fontMetrics = firstLineStyle().fontMetrics();
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003059 return Optional<int>(fontMetrics.ascent()
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003060 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003061 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()));
mmaxfield@apple.coma52ab462015-03-11 14:41:01 +00003062 }
3063
3064 if (auto simpleLineLayout = this->simpleLineLayout())
3065 lastBaseline = SimpleLineLayout::computeFlowLastLineBaseline(*this, *simpleLineLayout);
3066 else {
3067 bool isFirstLine = lastRootBox() == firstRootBox();
3068 const auto& style = isFirstLine ? firstLineStyle() : this->style();
3069 lastBaseline = lastRootBox()->logicalTop() + style.fontMetrics().ascent(lastRootBox()->baselineType());
3070 }
mmaxfield@apple.com9f4af632015-03-09 23:43:34 +00003071 }
3072 // According to the CSS spec http://www.w3.org/TR/CSS21/visudet.html, we shouldn't be performing this min, but should
3073 // instead be returning boxHeight directly. However, we feel that a min here is better behavior (and is consistent
3074 // enough with the spec to not cause tons of breakages).
mmaxfield@apple.com5f907742015-03-11 18:22:06 +00003075 return Optional<int>(style().overflowY() == OVISIBLE ? lastBaseline : std::min(boxHeight, lastBaseline));
weinig@apple.com611b9292013-10-20 22:57:54 +00003076}
3077
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003078void RenderBlockFlow::setSelectionState(SelectionState state)
3079{
3080 if (state != SelectionNone)
3081 ensureLineBoxes();
3082 RenderBoxModelObject::setSelectionState(state);
3083}
3084
weinig@apple.com12840dc2013-10-22 23:59:08 +00003085GapRects RenderBlockFlow::inlineSelectionGaps(RenderBlock& rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
weinig@apple.com611b9292013-10-20 22:57:54 +00003086 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const LogicalSelectionOffsetCaches& cache, const PaintInfo* paintInfo)
3087{
antti@apple.comfea51992013-10-28 13:39:23 +00003088 ASSERT(!m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003089
weinig@apple.com611b9292013-10-20 22:57:54 +00003090 GapRects result;
3091
3092 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3093
antti@apple.com0e632aa2013-10-22 21:03:38 +00003094 if (!hasLines()) {
weinig@apple.com611b9292013-10-20 22:57:54 +00003095 if (containsStart) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003096 // 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 +00003097 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3098 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight(), cache);
3099 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight(), cache);
3100 }
3101 return result;
3102 }
3103
3104 RootInlineBox* lastSelectedLine = 0;
3105 RootInlineBox* curr;
3106 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3107
3108 // Now paint the gaps for the lines.
3109 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3110 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3111 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3112
3113 if (!containsStart && !lastSelectedLine &&
hyatt@apple.com90a42042014-11-18 17:54:52 +00003114 selectionState() != SelectionStart && selectionState() != SelectionBoth && !isRubyBase())
weinig@apple.com611b9292013-10-20 22:57:54 +00003115 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, selTop, cache, paintInfo));
3116
3117 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3118 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
weinig@apple.com12840dc2013-10-22 23:59:08 +00003119 LayoutRect physicalRect = rootBlock.logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
weinig@apple.com611b9292013-10-20 22:57:54 +00003120 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3121 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3122 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, cache, paintInfo));
3123
3124 lastSelectedLine = curr;
3125 }
3126
3127 if (containsStart && !lastSelectedLine)
3128 // VisibleSelection must start just after our last line.
3129 lastSelectedLine = lastRootBox();
3130
3131 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00003132 // Update our lastY to be the bottom of the last selected line.
weinig@apple.com611b9292013-10-20 22:57:54 +00003133 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3134 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3135 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom(), cache);
3136 }
3137 return result;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00003138}
3139
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003140void RenderBlockFlow::createRenderNamedFlowFragmentIfNeeded()
3141{
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003142 if (!document().cssRegionsEnabled() || renderNamedFlowFragment() || isRenderNamedFlowFragment())
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003143 return;
3144
mihnea@adobe.com7c5101d2014-07-23 12:12:36 +00003145 // FIXME: Multicolumn regions not yet supported (http://dev.w3.org/csswg/css-regions/#multi-column-regions)
3146 if (style().isDisplayRegionType() && style().hasFlowFrom() && !style().specifiesColumns()) {
akling@apple.com827be9c2013-10-29 02:58:43 +00003147 RenderNamedFlowFragment* flowFragment = new RenderNamedFlowFragment(document(), RenderNamedFlowFragment::createStyle(style()));
akling@apple.com8f40c5b2013-10-27 22:54:07 +00003148 flowFragment->initializeStyle();
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003149 setRenderNamedFlowFragment(flowFragment);
3150 addChild(renderNamedFlowFragment());
3151 }
3152}
3153
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003154bool RenderBlockFlow::needsLayoutAfterRegionRangeChange() const
3155{
3156 // A block without floats or that expands to enclose them won't need a relayout
3157 // after a region range change. There is no overflow content needing relayout
3158 // in the region chain because the region range can only shrink after the estimation.
jfernandez@igalia.com136f1702014-12-08 19:13:16 +00003159 if (!containsFloats() || createsNewFormattingContext())
abucur@adobe.comeaf5e222014-05-14 14:35:07 +00003160 return false;
3161
3162 return true;
3163}
3164
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003165bool RenderBlockFlow::canHaveChildren() const
3166{
3167 return !renderNamedFlowFragment() ? RenderBlock::canHaveChildren() : renderNamedFlowFragment()->canHaveChildren();
3168}
3169
3170bool RenderBlockFlow::canHaveGeneratedChildren() const
3171{
3172 return !renderNamedFlowFragment() ? RenderBlock::canHaveGeneratedChildren() : renderNamedFlowFragment()->canHaveGeneratedChildren();
3173}
3174
3175bool RenderBlockFlow::namedFlowFragmentNeedsUpdate() const
3176{
3177 if (!isRenderNamedFlowFragmentContainer())
3178 return false;
3179
3180 return hasRelativeLogicalHeight() && !isRenderView();
3181}
3182
3183void RenderBlockFlow::updateLogicalHeight()
3184{
3185 RenderBlock::updateLogicalHeight();
3186
abucur@adobe.comfad53712014-05-06 17:30:40 +00003187 if (renderNamedFlowFragment()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003188 renderNamedFlowFragment()->setLogicalHeight(std::max<LayoutUnit>(0, logicalHeight() - borderAndPaddingLogicalHeight()));
abucur@adobe.comfad53712014-05-06 17:30:40 +00003189 renderNamedFlowFragment()->invalidateRegionIfNeeded();
3190 }
mihnea@adobe.combe79cf12013-10-17 09:02:19 +00003191}
3192
3193void RenderBlockFlow::setRenderNamedFlowFragment(RenderNamedFlowFragment* flowFragment)
3194{
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003195 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
abucur@adobe.com0e81bc72013-10-22 14:50:37 +00003196 if (rareData.m_renderNamedFlowFragment)
3197 rareData.m_renderNamedFlowFragment->destroy();
3198 rareData.m_renderNamedFlowFragment = flowFragment;
3199}
3200
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003201void RenderBlockFlow::setMultiColumnFlowThread(RenderMultiColumnFlowThread* flowThread)
3202{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003203 if (flowThread || hasRareBlockFlowData()) {
3204 RenderBlockFlowRareData& rareData = ensureRareBlockFlowData();
3205 rareData.m_multiColumnFlowThread = flowThread;
3206 }
hyatt@apple.come9fe3d32014-01-24 17:14:22 +00003207}
3208
akling@apple.com525dae62014-01-03 20:22:09 +00003209static bool shouldCheckLines(const RenderBlockFlow& blockFlow)
weinig@apple.com17140912013-10-19 19:55:40 +00003210{
akling@apple.com38f0a652014-02-06 21:24:17 +00003211 return !blockFlow.isFloatingOrOutOfFlowPositioned() && blockFlow.style().height().isAuto();
weinig@apple.com17140912013-10-19 19:55:40 +00003212}
3213
3214RootInlineBox* RenderBlockFlow::lineAtIndex(int i) const
3215{
3216 ASSERT(i >= 0);
3217
akling@apple.com827be9c2013-10-29 02:58:43 +00003218 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003219 return nullptr;
3220
3221 if (childrenInline()) {
3222 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3223 if (!i--)
3224 return box;
3225 }
akling@apple.com525dae62014-01-03 20:22:09 +00003226 return nullptr;
3227 }
3228
3229 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3230 if (!shouldCheckLines(blockFlow))
3231 continue;
3232 if (RootInlineBox* box = blockFlow.lineAtIndex(i))
3233 return box;
weinig@apple.com17140912013-10-19 19:55:40 +00003234 }
3235
3236 return nullptr;
3237}
3238
3239int RenderBlockFlow::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
3240{
akling@apple.com827be9c2013-10-29 02:58:43 +00003241 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003242 return 0;
3243
3244 int count = 0;
3245
3246 if (childrenInline()) {
darin@apple.come1be6ca2014-04-28 04:19:10 +00003247 if (auto simpleLineLayout = this->simpleLineLayout()) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003248 ASSERT(!stopRootInlineBox);
darin@apple.come1be6ca2014-04-28 04:19:10 +00003249 return simpleLineLayout->lineCount();
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003250 }
weinig@apple.com17140912013-10-19 19:55:40 +00003251 for (auto box = firstRootBox(); box; box = box->nextRootBox()) {
3252 count++;
3253 if (box == stopRootInlineBox) {
3254 if (found)
3255 *found = true;
3256 break;
3257 }
3258 }
akling@apple.com525dae62014-01-03 20:22:09 +00003259 return count;
3260 }
3261
3262 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3263 if (!shouldCheckLines(blockFlow))
3264 continue;
3265 bool recursiveFound = false;
3266 count += blockFlow.lineCount(stopRootInlineBox, &recursiveFound);
3267 if (recursiveFound) {
3268 if (found)
3269 *found = true;
3270 break;
weinig@apple.com17140912013-10-19 19:55:40 +00003271 }
3272 }
3273
3274 return count;
3275}
3276
3277static int getHeightForLineCount(const RenderBlockFlow& block, int lineCount, bool includeBottom, int& count)
3278{
akling@apple.com827be9c2013-10-29 02:58:43 +00003279 if (block.style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003280 return -1;
3281
3282 if (block.childrenInline()) {
3283 for (auto box = block.firstRootBox(); box; box = box->nextRootBox()) {
3284 if (++count == lineCount)
3285 return box->lineBottom() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
3286 }
3287 } else {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003288 RenderBox* normalFlowChildWithoutLines = nullptr;
weinig@apple.com17140912013-10-19 19:55:40 +00003289 for (auto obj = block.firstChildBox(); obj; obj = obj->nextSiblingBox()) {
cdumez@apple.com34e77ab2014-10-09 16:17:06 +00003290 if (is<RenderBlockFlow>(*obj) && shouldCheckLines(downcast<RenderBlockFlow>(*obj))) {
3291 int result = getHeightForLineCount(downcast<RenderBlockFlow>(*obj), lineCount, false, count);
weinig@apple.com17140912013-10-19 19:55:40 +00003292 if (result != -1)
3293 return result + obj->y() + (includeBottom ? (block.borderBottom() + block.paddingBottom()) : LayoutUnit());
akling@apple.com38f0a652014-02-06 21:24:17 +00003294 } else if (!obj->isFloatingOrOutOfFlowPositioned())
weinig@apple.com17140912013-10-19 19:55:40 +00003295 normalFlowChildWithoutLines = obj;
3296 }
3297 if (normalFlowChildWithoutLines && !lineCount)
3298 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
3299 }
3300
3301 return -1;
3302}
3303
3304int RenderBlockFlow::heightForLineCount(int lineCount)
3305{
3306 int count = 0;
3307 return getHeightForLineCount(*this, lineCount, true, count);
3308}
3309
3310void RenderBlockFlow::clearTruncation()
3311{
akling@apple.com827be9c2013-10-29 02:58:43 +00003312 if (style().visibility() != VISIBLE)
weinig@apple.com17140912013-10-19 19:55:40 +00003313 return;
3314
3315 if (childrenInline() && hasMarkupTruncation()) {
antti@apple.com940f5872013-10-24 20:31:11 +00003316 ensureLineBoxes();
3317
weinig@apple.com17140912013-10-19 19:55:40 +00003318 setHasMarkupTruncation(false);
3319 for (auto box = firstRootBox(); box; box = box->nextRootBox())
3320 box->clearTruncation();
akling@apple.com525dae62014-01-03 20:22:09 +00003321 return;
3322 }
3323
3324 for (auto& blockFlow : childrenOfType<RenderBlockFlow>(*this)) {
3325 if (shouldCheckLines(blockFlow))
3326 blockFlow.clearTruncation();
weinig@apple.com17140912013-10-19 19:55:40 +00003327 }
3328}
3329
weinig@apple.com3f23b382013-10-19 20:26:58 +00003330bool RenderBlockFlow::containsNonZeroBidiLevel() const
3331{
3332 for (auto root = firstRootBox(); root; root = root->nextRootBox()) {
3333 for (auto box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
3334 if (box->bidiLevel())
3335 return true;
3336 }
3337 }
3338 return false;
3339}
3340
weinig@apple.com611b9292013-10-20 22:57:54 +00003341Position RenderBlockFlow::positionForBox(InlineBox *box, bool start) const
3342{
3343 if (!box)
3344 return Position();
3345
3346 if (!box->renderer().nonPseudoNode())
3347 return createLegacyEditingPosition(nonPseudoElement(), start ? caretMinOffset() : caretMaxOffset());
3348
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003349 if (!is<InlineTextBox>(*box))
weinig@apple.com611b9292013-10-20 22:57:54 +00003350 return createLegacyEditingPosition(box->renderer().nonPseudoNode(), start ? box->renderer().caretMinOffset() : box->renderer().caretMaxOffset());
3351
cdumez@apple.com57d544c2014-10-16 00:05:37 +00003352 auto& textBox = downcast<InlineTextBox>(*box);
3353 return createLegacyEditingPosition(textBox.renderer().nonPseudoNode(), start ? textBox.start() : textBox.start() + textBox.len());
weinig@apple.com611b9292013-10-20 22:57:54 +00003354}
3355
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003356VisiblePosition RenderBlockFlow::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents, const RenderRegion* region)
weinig@apple.com611b9292013-10-20 22:57:54 +00003357{
3358 ASSERT(childrenInline());
3359
antti@apple.com940f5872013-10-24 20:31:11 +00003360 ensureLineBoxes();
3361
weinig@apple.com611b9292013-10-20 22:57:54 +00003362 if (!firstRootBox())
3363 return createVisiblePosition(0, DOWNSTREAM);
3364
akling@apple.com827be9c2013-10-29 02:58:43 +00003365 bool linesAreFlipped = style().isFlippedLinesWritingMode();
3366 bool blocksAreFlipped = style().isFlippedBlocksWritingMode();
weinig@apple.com611b9292013-10-20 22:57:54 +00003367
3368 // look for the closest line box in the root box which is at the passed-in y coordinate
3369 InlineBox* closestBox = 0;
3370 RootInlineBox* firstRootBoxWithChildren = 0;
3371 RootInlineBox* lastRootBoxWithChildren = 0;
3372 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003373 if (region && root->containingRegion() != region)
3374 continue;
3375
weinig@apple.com611b9292013-10-20 22:57:54 +00003376 if (!root->firstLeafChild())
3377 continue;
3378 if (!firstRootBoxWithChildren)
3379 firstRootBoxWithChildren = root;
3380
3381 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3382 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3383 break;
3384
3385 lastRootBoxWithChildren = root;
3386
3387 // check if this root line box is located at this y coordinate
3388 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3389 if (linesAreFlipped) {
3390 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3391 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3392 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3393
3394 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3395 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3396 continue;
3397 }
3398 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3399 if (closestBox)
3400 break;
3401 }
3402 }
3403
3404 bool moveCaretToBoundary = frame().editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3405
3406 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3407 // y coordinate is below last root line box, pretend we hit it
3408 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3409 }
3410
3411 if (closestBox) {
3412 if (moveCaretToBoundary) {
andersca@apple.com86298632013-11-10 19:32:33 +00003413 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
weinig@apple.com611b9292013-10-20 22:57:54 +00003414 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3415 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3416 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3417 if (box->isLineBreak()) {
3418 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3419 box = newBox;
3420 }
3421 // y coordinate is above first root line box, so return the start of the first
3422 return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
3423 }
3424 }
3425
3426 // pass the box a top position that is inside it
3427 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
3428 if (!isHorizontalWritingMode())
3429 point = point.transposedPoint();
3430 if (closestBox->renderer().isReplaced())
cdumez@apple.com0abff8b2014-10-17 21:25:10 +00003431 return positionForPointRespectingEditingBoundaries(*this, downcast<RenderBox>(closestBox->renderer()), point);
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003432 return closestBox->renderer().positionForPoint(point, nullptr);
weinig@apple.com611b9292013-10-20 22:57:54 +00003433 }
3434
3435 if (lastRootBoxWithChildren) {
3436 // We hit this case for Mac behavior when the Y coordinate is below the last box.
3437 ASSERT(moveCaretToBoundary);
3438 InlineBox* logicallyLastBox;
3439 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3440 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3441 }
3442
3443 // Can't reach this. We have a root line box, but it has no kids.
3444 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3445 // seems to hit this code path.
3446 return createVisiblePosition(0, DOWNSTREAM);
3447}
3448
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003449VisiblePosition RenderBlockFlow::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003450{
3451 if (auto fragment = renderNamedFlowFragment())
stavila@adobe.com4ce2fff2014-04-25 13:56:12 +00003452 return fragment->positionForPoint(point, region);
3453 return RenderBlock::positionForPoint(point, region);
commit-queue@webkit.org5ce6c902013-11-11 18:21:05 +00003454}
3455
3456
weinig@apple.com611b9292013-10-20 22:57:54 +00003457void RenderBlockFlow::addFocusRingRectsForInlineChildren(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
3458{
antti@apple.com940f5872013-10-24 20:31:11 +00003459 ASSERT(childrenInline());
3460
3461 ensureLineBoxes();
3462
weinig@apple.com611b9292013-10-20 22:57:54 +00003463 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
andersca@apple.com86298632013-11-10 19:32:33 +00003464 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
3465 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
weinig@apple.com611b9292013-10-20 22:57:54 +00003466 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
3467 if (!rect.isEmpty())
zalan@apple.com376339c2014-08-28 04:24:31 +00003468 rects.append(snappedIntRect(rect));
weinig@apple.com611b9292013-10-20 22:57:54 +00003469 }
3470}
3471
3472void RenderBlockFlow::paintInlineChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3473{
3474 ASSERT(childrenInline());
antti@apple.com940f5872013-10-24 20:31:11 +00003475
darin@apple.come1be6ca2014-04-28 04:19:10 +00003476 if (auto simpleLineLayout = this->simpleLineLayout()) {
3477 SimpleLineLayout::paintFlow(*this, *simpleLineLayout, paintInfo, paintOffset);
antti@apple.com940f5872013-10-24 20:31:11 +00003478 return;
3479 }
weinig@apple.com611b9292013-10-20 22:57:54 +00003480 m_lineBoxes.paint(this, paintInfo, paintOffset);
3481}
3482
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003483bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher)
weinig@apple.com611b9292013-10-20 22:57:54 +00003484{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003485 if (!multiColumnFlowThread() || !multiColumnFlowThread()->shouldRelayoutForPagination())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003486 return false;
3487
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003488 multiColumnFlowThread()->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003489 multiColumnFlowThread()->setInBalancingPass(true); // Prevent re-entering this method (and recursion into layout).
3490
3491 bool needsRelayout;
3492 bool neededRelayout = false;
3493 bool firstPass = true;
3494 do {
3495 // Column heights may change here because of balancing. We may have to do multiple layout
3496 // passes, depending on how the contents is fitted to the changed column heights. In most
3497 // cases, laying out again twice or even just once will suffice. Sometimes we need more
3498 // passes than that, though, but the number of retries should not exceed the number of
3499 // columns, unless we have a bug.
3500 needsRelayout = false;
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003501 for (RenderMultiColumnSet* multicolSet = multiColumnFlowThread()->firstMultiColumnSet(); multicolSet; multicolSet = multicolSet->nextSiblingMultiColumnSet()) {
3502 if (multicolSet->recalculateColumnHeight(firstPass))
3503 needsRelayout = true;
3504 if (needsRelayout) {
3505 // Once a column set gets a new column height, that column set and all successive column
3506 // sets need to be laid out over again, since their logical top will be affected by
3507 // this, and therefore their column heights may change as well, at least if the multicol
3508 // height is constrained.
3509 multicolSet->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003510 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003511 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003512 if (needsRelayout) {
3513 // Layout again. Column balancing resulted in a new height.
3514 neededRelayout = true;
3515 multiColumnFlowThread()->setChildNeedsLayout(MarkOnlyThis);
3516 setChildNeedsLayout(MarkOnlyThis);
3517 if (firstPass)
3518 statePusher.pop();
3519 layoutBlock(false);
3520 }
3521 firstPass = false;
3522 } while (needsRelayout);
3523
3524 multiColumnFlowThread()->setInBalancingPass(false);
3525
3526 return neededRelayout;
weinig@apple.com611b9292013-10-20 22:57:54 +00003527}
3528
antti@apple.com940f5872013-10-24 20:31:11 +00003529bool RenderBlockFlow::hasLines() const
3530{
3531 ASSERT(childrenInline());
3532
darin@apple.come1be6ca2014-04-28 04:19:10 +00003533 if (auto simpleLineLayout = this->simpleLineLayout())
3534 return simpleLineLayout->lineCount();
antti@apple.com940f5872013-10-24 20:31:11 +00003535
3536 return lineBoxes().firstLineBox();
3537}
3538
antti@apple.com9e891c82014-05-22 06:12:34 +00003539void RenderBlockFlow::invalidateLineLayoutPath()
3540{
akling@apple.coma12fee22015-02-01 02:58:13 +00003541 switch (lineLayoutPath()) {
antti@apple.com9e891c82014-05-22 06:12:34 +00003542 case UndeterminedPath:
3543 case ForceLineBoxesPath:
3544 ASSERT(!m_simpleLineLayout);
3545 return;
3546 case LineBoxesPath:
3547 ASSERT(!m_simpleLineLayout);
akling@apple.coma12fee22015-02-01 02:58:13 +00003548 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003549 return;
3550 case SimpleLinesPath:
3551 // The simple line layout may have become invalid.
3552 m_simpleLineLayout = nullptr;
3553 setNeedsLayout();
akling@apple.coma12fee22015-02-01 02:58:13 +00003554 setLineLayoutPath(UndeterminedPath);
antti@apple.com9e891c82014-05-22 06:12:34 +00003555 return;
3556 }
3557 ASSERT_NOT_REACHED();
3558}
3559
zalan@apple.come37da962014-12-11 03:29:29 +00003560void RenderBlockFlow::layoutSimpleLines(bool relayoutChildren, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom)
antti@apple.com940f5872013-10-24 20:31:11 +00003561{
zalan@apple.come37da962014-12-11 03:29:29 +00003562 bool needsLayout = selfNeedsLayout() || relayoutChildren || !m_simpleLineLayout;
3563 if (needsLayout) {
3564 deleteLineBoxesBeforeSimpleLineLayout();
3565 m_simpleLineLayout = SimpleLineLayout::create(*this);
3566 }
antti@apple.com940f5872013-10-24 20:31:11 +00003567 ASSERT(!m_lineBoxes.firstLineBox());
3568
antti@apple.comfea51992013-10-28 13:39:23 +00003569 LayoutUnit lineLayoutHeight = SimpleLineLayout::computeFlowHeight(*this, *m_simpleLineLayout);
antti@apple.com940f5872013-10-24 20:31:11 +00003570 LayoutUnit lineLayoutTop = borderAndPaddingBefore();
antti@apple.com940f5872013-10-24 20:31:11 +00003571 repaintLogicalTop = lineLayoutTop;
zalan@apple.come37da962014-12-11 03:29:29 +00003572 repaintLogicalBottom = needsLayout ? repaintLogicalTop + lineLayoutHeight : repaintLogicalTop;
antti@apple.com940f5872013-10-24 20:31:11 +00003573 setLogicalHeight(lineLayoutTop + lineLayoutHeight + borderAndPaddingAfter());
3574}
3575
3576void RenderBlockFlow::deleteLineBoxesBeforeSimpleLineLayout()
3577{
akling@apple.coma12fee22015-02-01 02:58:13 +00003578 ASSERT(lineLayoutPath() == SimpleLinesPath);
akling@apple.com31dd4f42013-10-30 22:27:59 +00003579 lineBoxes().deleteLineBoxes();
zalan@apple.com8bf2a912015-04-10 03:15:50 +00003580 for (auto& renderer : childrenOfType<RenderObject>(*this)) {
3581 if (is<RenderText>(renderer))
3582 downcast<RenderText>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3583 else if (is<RenderLineBreak>(renderer))
3584 downcast<RenderLineBreak>(renderer).deleteLineBoxesBeforeSimpleLineLayout();
3585 else
3586 ASSERT_NOT_REACHED();
3587 }
antti@apple.com940f5872013-10-24 20:31:11 +00003588}
3589
3590void RenderBlockFlow::ensureLineBoxes()
3591{
akling@apple.coma12fee22015-02-01 02:58:13 +00003592 setLineLayoutPath(ForceLineBoxesPath);
antti@apple.comfea51992013-10-28 13:39:23 +00003593 if (!m_simpleLineLayout)
antti@apple.com940f5872013-10-24 20:31:11 +00003594 return;
antti@apple.comfea51992013-10-28 13:39:23 +00003595 m_simpleLineLayout = nullptr;
antti@apple.com940f5872013-10-24 20:31:11 +00003596
3597#if !ASSERT_DISABLED
3598 LayoutUnit oldHeight = logicalHeight();
3599#endif
3600 bool didNeedLayout = needsLayout();
3601
3602 bool relayoutChildren = false;
3603 LayoutUnit repaintLogicalTop;
3604 LayoutUnit repaintLogicalBottom;
3605 layoutLineBoxes(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
3606
3607 updateLogicalHeight();
3608 ASSERT(didNeedLayout || logicalHeight() == oldHeight);
3609
3610 if (!didNeedLayout)
3611 clearNeedsLayout();
3612}
3613
simon.fraser@apple.comc9f96132015-03-06 18:20:40 +00003614#if ENABLE(TREE_DEBUGGING)
zalan@apple.comfac337f2014-08-29 17:55:34 +00003615void RenderBlockFlow::showLineTreeAndMark(const InlineBox* markedBox, int depth) const
weinig@apple.com611b9292013-10-20 22:57:54 +00003616{
weinig@apple.com611b9292013-10-20 22:57:54 +00003617 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
zalan@apple.comfac337f2014-08-29 17:55:34 +00003618 root->showLineTreeAndMark(markedBox, depth);
simon.fraser@apple.com3518b142014-09-03 21:18:05 +00003619
3620 if (auto simpleLineLayout = this->simpleLineLayout())
3621 SimpleLineLayout::showLineLayoutForFlow(*this, *simpleLineLayout, depth);
weinig@apple.com611b9292013-10-20 22:57:54 +00003622}
3623#endif
3624
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00003625RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
3626{
3627 if (hasRareBlockFlowData())
3628 return *m_rareBlockFlowData;
3629 materializeRareBlockFlowData();
3630 return *m_rareBlockFlowData;
3631}
3632
3633void RenderBlockFlow::materializeRareBlockFlowData()
3634{
3635 ASSERT(!hasRareBlockFlowData());
3636 m_rareBlockFlowData = std::make_unique<RenderBlockFlow::RenderBlockFlowRareData>(*this);
3637}
3638
aestes@apple.com6751d842014-01-12 02:51:25 +00003639#if ENABLE(IOS_TEXT_AUTOSIZING)
3640inline static bool isVisibleRenderText(RenderObject* renderer)
3641{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003642 if (!is<RenderText>(*renderer))
aestes@apple.com6751d842014-01-12 02:51:25 +00003643 return false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003644 RenderText& renderText = downcast<RenderText>(*renderer);
3645 return !renderText.linesBoundingBox().isEmpty() && !renderText.text()->containsOnlyWhitespace();
aestes@apple.com6751d842014-01-12 02:51:25 +00003646}
3647
3648inline static bool resizeTextPermitted(RenderObject* render)
3649{
3650 // We disallow resizing for text input fields and textarea to address <rdar://problem/5792987> and <rdar://problem/8021123>
3651 auto renderer = render->parent();
3652 while (renderer) {
3653 // Get the first non-shadow HTMLElement and see if it's an input.
cdumez@apple.coma9c60c92014-10-02 19:39:41 +00003654 if (is<HTMLElement>(renderer->element()) && !renderer->element()->isInShadowTree()) {
cdumez@apple.comcd131532014-09-27 01:32:34 +00003655 const HTMLElement& element = downcast<HTMLElement>(*renderer->element());
cdumez@apple.com59fdc8a2014-09-24 21:25:22 +00003656 return !is<HTMLInputElement>(element) && !is<HTMLTextAreaElement>(element);
aestes@apple.com6751d842014-01-12 02:51:25 +00003657 }
3658 renderer = renderer->parent();
3659 }
3660 return true;
3661}
3662
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003663int RenderBlockFlow::lineCountForTextAutosizing()
aestes@apple.com6751d842014-01-12 02:51:25 +00003664{
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003665 if (style().visibility() != VISIBLE)
3666 return 0;
3667 if (childrenInline())
3668 return lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003669 // Only descend into list items.
3670 int count = 0;
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003671 for (auto& listItem : childrenOfType<RenderListItem>(*this))
3672 count += listItem.lineCount();
aestes@apple.com6751d842014-01-12 02:51:25 +00003673 return count;
3674}
3675
3676static bool isNonBlocksOrNonFixedHeightListItems(const RenderObject* render)
3677{
3678 if (!render->isRenderBlock())
3679 return true;
3680 if (render->isListItem())
3681 return render->style().height().type() != Fixed;
3682 return false;
3683}
3684
3685// For now, we auto size single lines of text the same as multiple lines.
3686// We've been experimenting with low values for single lines of text.
3687static inline float oneLineTextMultiplier(float specifiedSize)
3688{
3689 return std::max((1.0f / log10f(specifiedSize) * 1.7f), 1.0f);
3690}
3691
3692static inline float textMultiplier(float specifiedSize)
3693{
3694 return std::max((1.0f / log10f(specifiedSize) * 1.95f), 1.0f);
3695}
3696
3697void RenderBlockFlow::adjustComputedFontSizes(float size, float visibleWidth)
3698{
3699 // Don't do any work if the block is smaller than the visible area.
3700 if (visibleWidth >= width())
3701 return;
3702
3703 unsigned lineCount;
3704 if (m_lineCountForTextAutosizing == NOT_SET) {
antti@apple.com0b3dffe2014-03-24 16:30:52 +00003705 int count = lineCountForTextAutosizing();
aestes@apple.com6751d842014-01-12 02:51:25 +00003706 if (!count)
3707 lineCount = NO_LINE;
3708 else if (count == 1)
3709 lineCount = ONE_LINE;
3710 else
3711 lineCount = MULTI_LINE;
3712 } else
3713 lineCount = m_lineCountForTextAutosizing;
3714
3715 ASSERT(lineCount != NOT_SET);
3716 if (lineCount == NO_LINE)
3717 return;
3718
3719 float actualWidth = m_widthForTextAutosizing != -1 ? static_cast<float>(m_widthForTextAutosizing) : static_cast<float>(width());
3720 float scale = visibleWidth / actualWidth;
3721 float minFontSize = roundf(size / scale);
3722
3723 for (RenderObject* descendent = traverseNext(this, isNonBlocksOrNonFixedHeightListItems); descendent; descendent = descendent->traverseNext(this, isNonBlocksOrNonFixedHeightListItems)) {
3724 if (isVisibleRenderText(descendent) && resizeTextPermitted(descendent)) {
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003725 RenderText& text = downcast<RenderText>(*descendent);
3726 RenderStyle& oldStyle = text.style();
antti@apple.com214b7162015-09-16 00:16:58 +00003727 auto fontDescription = oldStyle.fontDescription();
aestes@apple.com6751d842014-01-12 02:51:25 +00003728 float specifiedSize = fontDescription.specifiedSize();
3729 float scaledSize = roundf(specifiedSize * scale);
3730 if (scaledSize > 0 && scaledSize < minFontSize) {
3731 // Record the width of the block and the line count the first time we resize text and use it from then on for text resizing.
3732 // This makes text resizing consistent even if the block's width or line count changes (which can be caused by text resizing itself 5159915).
3733 if (m_lineCountForTextAutosizing == NOT_SET)
3734 m_lineCountForTextAutosizing = lineCount;
3735 if (m_widthForTextAutosizing == -1)
3736 m_widthForTextAutosizing = actualWidth;
3737
3738 float candidateNewSize = 0;
3739 float lineTextMultiplier = lineCount == ONE_LINE ? oneLineTextMultiplier(specifiedSize) : textMultiplier(specifiedSize);
3740 candidateNewSize = roundf(std::min(minFontSize, specifiedSize * lineTextMultiplier));
cdumez@apple.com35094bd2014-10-07 19:33:53 +00003741 if (candidateNewSize > specifiedSize && candidateNewSize != fontDescription.computedSize() && text.textNode() && oldStyle.textSizeAdjust().isAuto())
3742 document().addAutoSizingNode(text.textNode(), candidateNewSize);
aestes@apple.com6751d842014-01-12 02:51:25 +00003743 }
3744 }
3745 }
3746}
3747#endif // ENABLE(IOS_TEXT_AUTOSIZING)
3748
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003749RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren)
3750{
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003751 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread();
3752 if (!flowThread)
3753 return nullptr;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003754
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003755 setLogicalTopForChild(*flowThread, borderAndPaddingBefore());
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003756
3757 if (relayoutChildren)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003758 flowThread->setChildNeedsLayout(MarkOnlyThis);
3759
3760 if (flowThread->needsLayout()) {
3761 for (RenderMultiColumnSet* columnSet = flowThread->firstMultiColumnSet(); columnSet; columnSet = columnSet->nextSiblingMultiColumnSet())
3762 columnSet->prepareForLayout(!flowThread->inBalancingPass());
3763
3764 flowThread->invalidateRegions();
3765 flowThread->setNeedsHeightsRecalculation(true);
3766 flowThread->layout();
3767 } else {
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003768 // At the end of multicol layout, relayoutForPagination() is called unconditionally, but if
3769 // no children are to be laid out (e.g. fixed width with layout already being up-to-date),
3770 // we want to prevent it from doing any work, so that the column balancing machinery doesn't
3771 // kick in and trigger additional unnecessary layout passes. Actually, it's not just a good
3772 // idea in general to not waste time on balancing content that hasn't been re-laid out; we
3773 // are actually required to guarantee this. The calculation of implicit breaks needs to be
3774 // preceded by a proper layout pass, since it's layout that sets up content runs, and the
3775 // runs get deleted right after every pass.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003776 flowThread->setNeedsHeightsRecalculation(false);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003777 }
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003778 determineLogicalLeftPositionForChild(*flowThread);
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003779
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003780 return flowThread;
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003781}
3782
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003783void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild)
3784{
3785 if (multiColumnFlowThread())
3786 return multiColumnFlowThread()->addChild(newChild, beforeChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003787 if (beforeChild) {
3788 if (RenderFlowThread* containingFlowThread = flowThreadContainingBlock())
3789 beforeChild = containingFlowThread->resolveMovedChild(beforeChild);
3790 }
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003791 RenderBlock::addChild(newChild, beforeChild);
3792}
3793
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003794void RenderBlockFlow::removeChild(RenderObject& oldChild)
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003795{
3796 if (!documentBeingDestroyed()) {
3797 RenderFlowThread* flowThread = multiColumnFlowThread();
3798 if (flowThread && flowThread != &oldChild)
3799 flowThread->flowThreadRelativeWillBeRemoved(&oldChild);
3800 }
akling@apple.comd0fd8ee2014-11-21 23:39:16 +00003801 RenderBlock::removeChild(oldChild);
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003802}
3803
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003804void RenderBlockFlow::checkForPaginationLogicalHeightChange(bool& relayoutChildren, LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged)
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003805{
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003806 // If we don't use columns or flow threads, then bail.
3807 if (!isRenderFlowThread() && !multiColumnFlowThread())
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003808 return;
3809
3810 // We don't actually update any of the variables. We just subclassed to adjust our column height.
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003811 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) {
3812 LogicalExtentComputedValues computedValues;
3813 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues);
3814 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight();
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003815 LayoutUnit oldHeightAvailable = flowThread->columnHeightAvailable();
hyatt@apple.comc1c39032014-04-15 23:25:58 +00003816 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0));
hyatt@apple.comc9d96572014-04-21 20:20:27 +00003817 if (oldHeightAvailable != flowThread->columnHeightAvailable())
3818 relayoutChildren = true;
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003819 } else if (is<RenderFlowThread>(*this)) {
3820 RenderFlowThread& flowThread = downcast<RenderFlowThread>(*this);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003821
3822 // FIXME: This is a hack to always make sure we have a page logical height, if said height
3823 // is known. The page logical height thing in LayoutState is meaningless for flow
3824 // thread-based pagination (page height isn't necessarily uniform throughout the flow
3825 // thread), but as long as it is used universally as a means to determine whether page
3826 // height is known or not, we need this. Page height is unknown when column balancing is
3827 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When
3828 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere
3829 // and thereby eating every top margin. It should be trivial to clean up and get rid of this
3830 // hack once the old multicol implementation is gone.
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003831 pageLogicalHeight = flowThread.isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0);
commit-queue@webkit.org3d0f60b2014-04-08 18:19:47 +00003832
cdumez@apple.com3abcc792014-10-20 03:42:03 +00003833 pageLogicalHeightChanged = flowThread.pageLogicalSizeChanged();
hyatt@apple.comd4be3772014-01-24 19:55:33 +00003834 }
3835}
3836
hyatt@apple.com73715ca2014-05-06 21:35:52 +00003837bool RenderBlockFlow::requiresColumns(int desiredColumnCount) const
3838{
3839 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3840 // in the RenderView instead.
3841 bool isPaginated = (style().overflowY() == OPAGEDX || style().overflowY() == OPAGEDY) && !(isRoot() || isBody());
3842
3843 return firstChild() && (desiredColumnCount != 1 || !style().hasAutoColumnWidth() || !style().hasInlineColumnAxis() || isPaginated);
3844}
3845
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003846void RenderBlockFlow::setComputedColumnCountAndWidth(int count, LayoutUnit width)
3847{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003848 bool destroyColumns = !requiresColumns(count);
3849 if (destroyColumns) {
3850 if (multiColumnFlowThread())
3851 destroyMultiColumnFlowThread();
3852 } else {
3853 if (!multiColumnFlowThread())
3854 createMultiColumnFlowThread();
3855 multiColumnFlowThread()->setColumnCountAndWidth(count, width);
hyatt@apple.com86919862014-01-27 16:27:45 +00003856 multiColumnFlowThread()->setProgressionIsInline(style().hasInlineColumnAxis());
3857 multiColumnFlowThread()->setProgressionIsReversed(style().columnProgression() == ReverseColumnProgression);
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003858 }
3859}
3860
cdumez@apple.com78141732014-11-04 23:00:48 +00003861void RenderBlockFlow::updateColumnProgressionFromStyle(RenderStyle& style)
hyatt@apple.com86919862014-01-27 16:27:45 +00003862{
hyatt@apple.com86919862014-01-27 16:27:45 +00003863 if (!multiColumnFlowThread())
3864 return;
3865
3866 bool needsLayout = false;
3867 bool oldProgressionIsInline = multiColumnFlowThread()->progressionIsInline();
cdumez@apple.com78141732014-11-04 23:00:48 +00003868 bool newProgressionIsInline = style.hasInlineColumnAxis();
hyatt@apple.com86919862014-01-27 16:27:45 +00003869 if (oldProgressionIsInline != newProgressionIsInline) {
3870 multiColumnFlowThread()->setProgressionIsInline(newProgressionIsInline);
3871 needsLayout = true;
3872 }
3873
3874 bool oldProgressionIsReversed = multiColumnFlowThread()->progressionIsReversed();
cdumez@apple.com78141732014-11-04 23:00:48 +00003875 bool newProgressionIsReversed = style.columnProgression() == ReverseColumnProgression;
hyatt@apple.com86919862014-01-27 16:27:45 +00003876 if (oldProgressionIsReversed != newProgressionIsReversed) {
3877 multiColumnFlowThread()->setProgressionIsReversed(newProgressionIsReversed);
3878 needsLayout = true;
3879 }
3880
3881 if (needsLayout)
3882 setNeedsLayoutAndPrefWidthsRecalc();
3883}
3884
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003885LayoutUnit RenderBlockFlow::computedColumnWidth() const
3886{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003887 if (multiColumnFlowThread())
3888 return multiColumnFlowThread()->computedColumnWidth();
3889 return contentLogicalWidth();
3890}
3891
3892unsigned RenderBlockFlow::computedColumnCount() const
3893{
hyatt@apple.com39746fd2014-01-24 22:52:41 +00003894 if (multiColumnFlowThread())
3895 return multiColumnFlowThread()->computedColumnCount();
3896
3897 return 1;
3898}
3899
hyatt@apple.com31a5daa2014-01-28 01:26:37 +00003900bool RenderBlockFlow::isTopLayoutOverflowAllowed() const
3901{
3902 bool hasTopOverflow = RenderBlock::isTopLayoutOverflowAllowed();
3903 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3904 return hasTopOverflow;
3905
3906 if (!(isHorizontalWritingMode() ^ !style().hasInlineColumnAxis()))
3907 hasTopOverflow = !hasTopOverflow;
3908
3909 return hasTopOverflow;
3910}
3911
3912bool RenderBlockFlow::isLeftLayoutOverflowAllowed() const
3913{
3914 bool hasLeftOverflow = RenderBlock::isLeftLayoutOverflowAllowed();
3915 if (!multiColumnFlowThread() || style().columnProgression() == NormalColumnProgression)
3916 return hasLeftOverflow;
3917
3918 if (isHorizontalWritingMode() ^ !style().hasInlineColumnAxis())
3919 hasLeftOverflow = !hasLeftOverflow;
3920
3921 return hasLeftOverflow;
3922}
3923
zalan@apple.comac6956c2014-09-05 14:18:06 +00003924struct InlineMinMaxIterator {
3925/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3926 inline min/max width calculations. Note the following about the way it walks:
3927 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3928 (2) We do not drill into the children of floats or replaced elements, since you can't break
3929 in the middle of such an element.
3930 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3931 distinct borders/margin/padding that contribute to the min/max width.
3932*/
3933 const RenderBlockFlow& parent;
3934 RenderObject* current;
3935 bool endOfInline;
3936 bool initial;
3937
3938 InlineMinMaxIterator(const RenderBlockFlow& p)
3939 : parent(p)
3940 , current(nullptr)
3941 , endOfInline(false)
3942 , initial(true)
3943 { }
3944
3945 RenderObject* next();
3946};
3947
3948RenderObject* InlineMinMaxIterator::next()
3949{
3950 RenderObject* result = nullptr;
3951 bool oldEndOfInline = endOfInline;
3952 endOfInline = false;
3953 do {
3954 if (!oldEndOfInline && (current && !current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))
3955 result = current->firstChildSlow();
3956 else if (initial) {
3957 result = parent.firstChild();
3958 initial = false;
3959 }
3960
3961 if (!result) {
3962 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3963 if (!oldEndOfInline && current && current->isRenderInline()) {
3964 result = current;
3965 endOfInline = true;
3966 break;
3967 }
3968
3969 while (current && current != &parent) {
3970 result = current->nextSibling();
3971 if (result)
3972 break;
3973 current = current->parent();
3974 if (current && current != &parent && current->isRenderInline()) {
3975 result = current;
3976 endOfInline = true;
3977 break;
3978 }
3979 }
3980 }
3981
3982 if (!result)
3983 break;
3984
3985 if (!result->isOutOfFlowPositioned() && (result->isTextOrLineBreak() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
3986 break;
3987
3988 current = result;
3989 result = nullptr;
3990 } while (current || current == &parent);
3991 // Update our position.
3992 current = result;
3993 return result;
3994}
3995
3996static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
3997{
3998 if (cssUnit.type() != Auto)
3999 return (cssUnit.isFixed() ? LayoutUnit(cssUnit.value()) : childValue);
4000 return 0;
4001}
4002
4003static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject& child, bool endOfInline)
4004{
4005 const RenderStyle& childStyle = child.style();
4006 if (endOfInline) {
4007 return getBPMWidth(child.marginEnd(), childStyle.marginEnd()) +
4008 getBPMWidth(child.paddingEnd(), childStyle.paddingEnd()) +
4009 child.borderEnd();
4010 }
4011 return getBPMWidth(child.marginStart(), childStyle.marginStart()) +
4012 getBPMWidth(child.paddingStart(), childStyle.paddingStart()) +
4013 child.borderStart();
4014}
4015
4016static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, RenderObject* trailingSpaceChild)
4017{
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004018 if (is<RenderText>(trailingSpaceChild)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004019 // Collapse away the trailing space at the end of a block.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004020 RenderText& renderText = downcast<RenderText>(*trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004021 const UChar space = ' ';
antti@apple.comc54cbc92015-01-15 14:19:56 +00004022 const FontCascade& font = renderText.style().fontCascade(); // FIXME: This ignores first-line.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004023 float spaceWidth = font.width(RenderBlock::constructTextRun(&renderText, font, &space, 1, renderText.style()));
zalan@apple.comac6956c2014-09-05 14:18:06 +00004024 inlineMax -= spaceWidth + font.wordSpacing();
4025 if (inlineMin > inlineMax)
4026 inlineMin = inlineMax;
4027 }
4028}
4029
4030static inline LayoutUnit preferredWidth(LayoutUnit preferredWidth, float result)
4031{
4032 return std::max(preferredWidth, LayoutUnit::fromFloatCeil(result));
4033}
4034
4035void RenderBlockFlow::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4036{
4037 float inlineMax = 0;
4038 float inlineMin = 0;
4039
4040 const RenderStyle& styleToUse = style();
4041 RenderBlock* containingBlock = this->containingBlock();
4042 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4043
4044 // If we are at the start of a line, we want to ignore all white-space.
4045 // Also strip spaces if we previously had text that ended in a trailing space.
4046 bool stripFrontSpaces = true;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004047 RenderObject* trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004048
4049 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4050 // very specific cirucumstances (in order to match common WinIE renderings).
4051 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4052 bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse.logicalWidth().isIntrinsicOrAuto();
4053
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004054 bool oldAutoWrap = styleToUse.autoWrap();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004055
4056 InlineMinMaxIterator childIterator(*this);
4057
4058 // Only gets added to the max preffered width once.
4059 bool addedTextIndent = false;
4060 // Signals the text indent was more negative than the min preferred width
4061 bool hasRemainingNegativeTextIndent = false;
4062
4063 LayoutUnit textIndent = minimumValueForLength(styleToUse.textIndent(), cw);
4064 RenderObject* prevFloat = 0;
4065 bool isPrevChildInlineFlow = false;
4066 bool shouldBreakLineAfterText = false;
4067 while (RenderObject* child = childIterator.next()) {
cdumez@apple.comc28103d52014-10-31 23:25:05 +00004068 bool autoWrap = child->isReplaced() ? child->parent()->style().autoWrap() :
zalan@apple.comac6956c2014-09-05 14:18:06 +00004069 child->style().autoWrap();
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004070 bool isAnonymousInlineBlock = child->isAnonymousInlineBlock();
4071
zalan@apple.comac6956c2014-09-05 14:18:06 +00004072 if (!child->isBR()) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004073 // Step One: determine whether or not we need to terminate our current line.
4074 // Each discrete chunk can become the new min-width, if it is the widest chunk
4075 // seen so far, and it can also become the max-width.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004076
4077 // Children fall into three categories:
4078 // (1) An inline flow object. These objects always have a min/max of 0,
4079 // and are included in the iteration solely so that their margins can
4080 // be added in.
4081 //
4082 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4083 // These objects can always be on a line by themselves, so in this situation
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004084 // we need to break the current line, and then add in our own margins and min/max
4085 // width on its own line, and then terminate the line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004086 //
4087 // (3) A text object. Text runs can have breakable characters at the start,
4088 // the middle or the end. They may also lose whitespace off the front if
4089 // we're already ignoring whitespace. In order to compute accurate min-width
4090 // information, we need three pieces of information.
4091 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4092 // starts with whitespace.
4093 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4094 // ends with whitespace.
4095 // (c) the min/max width of the string (trimmed for whitespace).
4096 //
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004097 // If the text string starts with whitespace, then we need to terminate our current line
4098 // (unless we're already in a whitespace stripping mode.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004099 //
4100 // If the text string has a breakable character in the middle, but didn't start
4101 // with whitespace, then we add the width of the first non-breakable run and
4102 // then end the current line. We then need to use the intermediate min/max width
4103 // values (if any of them are larger than our current min/max). We then look at
4104 // the width of the last non-breakable run and use that to start a new line
4105 // (unless we end in whitespace).
4106 const RenderStyle& childStyle = child->style();
4107 float childMin = 0;
4108 float childMax = 0;
4109
4110 if (!child->isText()) {
4111 if (child->isLineBreakOpportunity()) {
4112 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4113 inlineMin = 0;
4114 continue;
4115 }
4116 // Case (1) and (2). Inline replaced and inline flow elements.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004117 if (is<RenderInline>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004118 // Add in padding/border/margin from the appropriate side of
4119 // the element.
cdumez@apple.comf8022152014-10-15 00:29:51 +00004120 float bpm = getBorderPaddingMargin(downcast<RenderInline>(*child), childIterator.endOfInline);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004121 childMin += bpm;
4122 childMax += bpm;
4123
4124 inlineMin += childMin;
4125 inlineMax += childMax;
4126
4127 child->setPreferredLogicalWidthsDirty(false);
4128 } else {
4129 // Inline replaced elts add in their margins to their min/max values.
4130 LayoutUnit margins = 0;
4131 Length startMargin = childStyle.marginStart();
4132 Length endMargin = childStyle.marginEnd();
4133 if (startMargin.isFixed())
4134 margins += LayoutUnit::fromFloatCeil(startMargin.value());
4135 if (endMargin.isFixed())
4136 margins += LayoutUnit::fromFloatCeil(endMargin.value());
4137 childMin += margins.ceilToFloat();
4138 childMax += margins.ceilToFloat();
4139 }
4140 }
4141
cdumez@apple.comf8022152014-10-15 00:29:51 +00004142 if (!is<RenderInline>(*child) && !is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004143 // Case (2). Inline replaced elements and floats.
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004144 // Terminate the current line as far as minwidth is concerned.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004145 childMin += child->minPreferredLogicalWidth().ceilToFloat();
4146 childMax += child->maxPreferredLogicalWidth().ceilToFloat();
4147
4148 bool clearPreviousFloat;
4149 if (child->isFloating()) {
4150 clearPreviousFloat = (prevFloat
4151 && ((prevFloat->style().floating() == LeftFloat && (childStyle.clear() & CLEFT))
4152 || (prevFloat->style().floating() == RightFloat && (childStyle.clear() & CRIGHT))));
4153 prevFloat = child;
4154 } else
4155 clearPreviousFloat = false;
4156
4157 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004158 if (((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) || isAnonymousInlineBlock) {
4159 if (child->isAnonymousInlineBlock() && styleToUse.collapseWhiteSpace())
4160 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004161 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4162 inlineMin = 0;
4163 }
4164
4165 // If we're supposed to clear the previous float, then terminate maxwidth as well.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004166 if (clearPreviousFloat || isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004167 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4168 inlineMax = 0;
4169 }
4170
4171 // Add in text-indent. This is added in only once.
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004172 if (!addedTextIndent && !child->isFloating() && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004173 LayoutUnit ceiledIndent = textIndent.ceilToFloat();
4174 childMin += ceiledIndent;
4175 childMax += ceiledIndent;
4176
4177 if (childMin < 0)
4178 textIndent = LayoutUnit::fromFloatCeil(childMin);
4179 else
4180 addedTextIndent = true;
4181 }
4182
4183 // Add our width to the max.
4184 inlineMax += std::max<float>(0, childMax);
4185
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004186 if ((!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) && !isAnonymousInlineBlock) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004187 if (child->isFloating())
4188 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4189 else
4190 inlineMin += childMin;
4191 } else {
4192 // Now check our line.
4193 minLogicalWidth = preferredWidth(minLogicalWidth, childMin);
4194
4195 // Now start a new line.
4196 inlineMin = 0;
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004197
4198 if (child->isAnonymousInlineBlock()) {
4199 // Terminate max width as well.
4200 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4201 inlineMax = 0;
4202 }
zalan@apple.comac6956c2014-09-05 14:18:06 +00004203 }
4204
4205 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4206 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4207 inlineMin = 0;
4208 }
4209
4210 // We are no longer stripping whitespace at the start of a line.
4211 if (!child->isFloating()) {
4212 stripFrontSpaces = false;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004213 trailingSpaceChild = nullptr;
zalan@apple.comac6956c2014-09-05 14:18:06 +00004214 }
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004215 } else if (is<RenderText>(*child)) {
zalan@apple.comac6956c2014-09-05 14:18:06 +00004216 // Case (3). Text.
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004217 RenderText& renderText = downcast<RenderText>(*child);
zalan@apple.comac6956c2014-09-05 14:18:06 +00004218
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004219 if (renderText.style().hasTextCombine() && renderText.isCombineText())
4220 downcast<RenderCombineText>(renderText).combineText();
zalan@apple.comac6956c2014-09-05 14:18:06 +00004221
4222 // Determine if we have a breakable character. Pass in
4223 // whether or not we should ignore any spaces at the front
4224 // of the string. If those are going to be stripped out,
4225 // then they shouldn't be considered in the breakable char
4226 // check.
4227 bool hasBreakableChar, hasBreak;
4228 float beginMin, endMin;
4229 bool beginWS, endWS;
4230 float beginMax, endMax;
cdumez@apple.com35094bd2014-10-07 19:33:53 +00004231 renderText.trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
zalan@apple.comac6956c2014-09-05 14:18:06 +00004232 hasBreakableChar, hasBreak, beginMax, endMax,
4233 childMin, childMax, stripFrontSpaces);
4234
4235 // This text object will not be rendered, but it may still provide a breaking opportunity.
4236 if (!hasBreak && !childMax) {
4237 if (autoWrap && (beginWS || endWS)) {
4238 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4239 inlineMin = 0;
4240 }
4241 continue;
4242 }
4243
4244 if (stripFrontSpaces)
4245 trailingSpaceChild = child;
4246 else
4247 trailingSpaceChild = 0;
4248
4249 // Add in text-indent. This is added in only once.
4250 float ti = 0;
4251 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4252 ti = textIndent.ceilToFloat();
4253 childMin += ti;
4254 beginMin += ti;
4255
4256 // It the text indent negative and larger than the child minimum, we re-use the remainder
4257 // in future minimum calculations, but using the negative value again on the maximum
4258 // will lead to under-counting the max pref width.
4259 if (!addedTextIndent) {
4260 childMax += ti;
4261 beginMax += ti;
4262 addedTextIndent = true;
4263 }
4264
4265 if (childMin < 0) {
4266 textIndent = childMin;
4267 hasRemainingNegativeTextIndent = true;
4268 }
4269 }
4270
4271 // If we have no breakable characters at all,
4272 // then this is the easy case. We add ourselves to the current
4273 // min and max and continue.
4274 if (!hasBreakableChar)
4275 inlineMin += childMin;
4276 else {
4277 // We have a breakable character. Now we need to know if
4278 // we start and end with whitespace.
4279 if (beginWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004280 // End the current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004281 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4282 } else {
4283 inlineMin += beginMin;
4284 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4285 childMin -= ti;
4286 }
4287
4288 inlineMin = childMin;
4289
4290 if (endWS) {
simon.fraser@apple.com03e61032015-04-05 20:17:11 +00004291 // We end in whitespace, which means we can end our current line.
zalan@apple.comac6956c2014-09-05 14:18:06 +00004292 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4293 inlineMin = 0;
4294 shouldBreakLineAfterText = false;
4295 } else {
4296 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4297 inlineMin = endMin;
4298 shouldBreakLineAfterText = true;
4299 }
4300 }
4301
4302 if (hasBreak) {
4303 inlineMax += beginMax;
4304 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4305 maxLogicalWidth = preferredWidth(maxLogicalWidth, childMax);
4306 inlineMax = endMax;
4307 addedTextIndent = true;
4308 } else
4309 inlineMax += std::max<float>(0, childMax);
4310 }
4311
hyatt@apple.comdafe5972015-03-31 17:42:24 +00004312 // Ignore spaces after a list marker and also after an anonymous inline block.
4313 if (child->isListMarker() || isAnonymousInlineBlock)
zalan@apple.comac6956c2014-09-05 14:18:06 +00004314 stripFrontSpaces = true;
4315 } else {
4316 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4317 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4318 inlineMin = inlineMax = 0;
4319 stripFrontSpaces = true;
4320 trailingSpaceChild = 0;
4321 addedTextIndent = true;
4322 }
4323
4324 if (!child->isText() && child->isRenderInline())
4325 isPrevChildInlineFlow = true;
4326 else
4327 isPrevChildInlineFlow = false;
4328
4329 oldAutoWrap = autoWrap;
4330 }
4331
4332 if (styleToUse.collapseWhiteSpace())
4333 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4334
4335 minLogicalWidth = preferredWidth(minLogicalWidth, inlineMin);
4336 maxLogicalWidth = preferredWidth(maxLogicalWidth, inlineMax);
4337}
4338
hyatt@apple.come96ebaf2013-11-12 22:51:12 +00004339}
4340// namespace WebCore