Add WTF::move()
[WebKit-https.git] / Source / WebCore / rendering / RenderFlowThread.cpp
1 /*
2  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "RenderFlowThread.h"
32
33 #include "FlowThreadController.h"
34 #include "HitTestRequest.h"
35 #include "HitTestResult.h"
36 #include "InlineElementBox.h"
37 #include "Node.h"
38 #include "PODIntervalTree.h"
39 #include "PaintInfo.h"
40 #include "RenderBoxRegionInfo.h"
41 #include "RenderInline.h"
42 #include "RenderLayer.h"
43 #include "RenderLayerCompositor.h"
44 #include "RenderNamedFlowFragment.h"
45 #include "RenderRegion.h"
46 #include "RenderTheme.h"
47 #include "RenderView.h"
48 #include "TransformState.h"
49 #include "WebKitNamedFlow.h"
50 #include <wtf/StackStats.h>
51
52 namespace WebCore {
53
54 RenderFlowThread::RenderFlowThread(Document& document, PassRef<RenderStyle> style)
55     : RenderBlockFlow(document, WTF::move(style))
56     , m_previousRegionCount(0)
57     , m_autoLogicalHeightRegionsCount(0)
58     , m_currentRegionMaintainer(nullptr)
59     , m_regionsInvalidated(false)
60     , m_regionsHaveUniformLogicalWidth(true)
61     , m_regionsHaveUniformLogicalHeight(true)
62     , m_pageLogicalSizeChanged(false)
63     , m_layoutPhase(LayoutPhaseMeasureContent)
64     , m_needsTwoPhasesLayout(false)
65     , m_layersToRegionMappingsDirty(true)
66 {
67     setFlowThreadState(InsideOutOfFlowThread);
68 }
69
70 PassRef<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* parentStyle)
71 {
72     auto newStyle = RenderStyle::create();
73     newStyle.get().inheritFrom(parentStyle);
74     newStyle.get().setDisplay(BLOCK);
75     newStyle.get().setPosition(AbsolutePosition);
76     newStyle.get().setZIndex(0);
77     newStyle.get().setLeft(Length(0, Fixed));
78     newStyle.get().setTop(Length(0, Fixed));
79     newStyle.get().setWidth(Length(100, Percent));
80     newStyle.get().setHeight(Length(100, Percent));
81     newStyle.get().font().update(0);
82     return newStyle;
83 }
84
85 void RenderFlowThread::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
86 {
87     RenderBlockFlow::styleDidChange(diff, oldStyle);
88
89     if (oldStyle && oldStyle->writingMode() != style().writingMode())
90         invalidateRegions();
91 }
92
93 void RenderFlowThread::removeFlowChildInfo(RenderObject* child)
94 {
95     if (child->isRenderBlockFlow())
96         removeLineRegionInfo(toRenderBlockFlow(child));
97     if (child->isBox())
98         removeRenderBoxRegionInfo(toRenderBox(child));
99 }
100
101 void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
102 {
103     ASSERT(renderRegion);
104     m_regionList.remove(renderRegion);
105 }
106
107 void RenderFlowThread::invalidateRegions()
108 {
109     ASSERT(!inFinalLayoutPhase());
110
111     if (m_regionsInvalidated) {
112         ASSERT(selfNeedsLayout());
113         return;
114     }
115
116     m_regionRangeMap.clear();
117     m_breakBeforeToRegionMap.clear();
118     m_breakAfterToRegionMap.clear();
119     if (m_layerToRegionMap)
120         m_layerToRegionMap->clear();
121     if (m_regionToLayerListMap)
122         m_regionToLayerListMap->clear();
123     if (m_lineToRegionMap)
124         m_lineToRegionMap->clear();
125     m_layersToRegionMappingsDirty = true;
126     setNeedsLayout();
127
128     m_regionsInvalidated = true;
129 }
130
131 void RenderFlowThread::validateRegions()
132 {
133     if (m_regionsInvalidated) {
134         m_regionsInvalidated = false;
135         m_regionsHaveUniformLogicalWidth = true;
136         m_regionsHaveUniformLogicalHeight = true;
137
138         if (hasRegions()) {
139             LayoutUnit previousRegionLogicalWidth = 0;
140             LayoutUnit previousRegionLogicalHeight = 0;
141             bool firstRegionVisited = false;
142             
143             for (auto& region : m_regionList) {
144                 ASSERT(!region->needsLayout() || region->isRenderRegionSet());
145
146                 region->deleteAllRenderBoxRegionInfo();
147
148                 // In the measure content layout phase we need to initialize the computedAutoHeight for auto-height regions.
149                 // See initializeRegionsComputedAutoHeight for the explanation.
150                 // Also, if we have auto-height regions we can't assume m_regionsHaveUniformLogicalHeight to be true in the first phase
151                 // because the auto-height regions don't have their height computed yet.
152                 if (inMeasureContentLayoutPhase() && region->hasAutoLogicalHeight()) {
153                     RenderNamedFlowFragment* namedFlowFragment = toRenderNamedFlowFragment(region);
154                     namedFlowFragment->setComputedAutoHeight(namedFlowFragment->maxPageLogicalHeight());
155                     m_regionsHaveUniformLogicalHeight = false;
156                 }
157
158                 LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
159                 LayoutUnit regionLogicalHeight = region->pageLogicalHeight();
160
161                 if (!firstRegionVisited)
162                     firstRegionVisited = true;
163                 else {
164                     if (m_regionsHaveUniformLogicalWidth && previousRegionLogicalWidth != regionLogicalWidth)
165                         m_regionsHaveUniformLogicalWidth = false;
166                     if (m_regionsHaveUniformLogicalHeight && previousRegionLogicalHeight != regionLogicalHeight)
167                         m_regionsHaveUniformLogicalHeight = false;
168                 }
169
170                 previousRegionLogicalWidth = regionLogicalWidth;
171             }
172
173             setRegionRangeForBox(this, m_regionList.first(), m_regionList.last());
174         }
175     }
176
177     updateLogicalWidth(); // Called to get the maximum logical width for the region.
178     updateRegionsFlowThreadPortionRect();
179 }
180
181 void RenderFlowThread::layout()
182 {
183     StackStats::LayoutCheckPoint layoutCheckPoint;
184
185     m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout();
186
187     // In case this is the second pass of the measure content phase we need to update the auto-height regions to their initial value.
188     // If the region chain was invalidated this will happen anyway.
189     if (!m_regionsInvalidated && inMeasureContentLayoutPhase())
190         initializeRegionsComputedAutoHeight();
191
192     // This is the first phase of the layout and because we have auto-height regions we'll need a second
193     // pass to update the flow with the computed auto-height regions.
194     // It's also possible to need a secondary layout if the overflow computation invalidated the region chain (e.g. overflow: auto scrollbars
195     // shrunk some regions) so repropagation is required.
196     m_needsTwoPhasesLayout = (inMeasureContentLayoutPhase() && hasAutoLogicalHeightRegions()) || (inOverflowLayoutPhase() && m_regionsInvalidated);
197
198     validateRegions();
199
200     CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this);
201     RenderBlockFlow::layout();
202
203     m_pageLogicalSizeChanged = false;
204
205     // If there are children layers in the RenderFlowThread then we need to make sure that the
206     // composited children layers will land in the right RenderRegions. Also, the parent RenderRegions
207     // will get RenderLayers and become composited as needed.
208     // Note that there's no need to do so for the inline multi-column as we are not moving layers into different
209     // containers, but just adjusting the position of the RenderLayerBacking.
210     if (!m_needsTwoPhasesLayout) {
211         // If we have layers that moved from one region to another, we trigger
212         // a composited layers rebuild in here to make sure that the regions will collect the right layers.
213         if (updateAllLayerToRegionMappings())
214             layer()->compositor().setCompositingLayersNeedRebuild();
215     }
216 }
217
218 bool RenderFlowThread::hasCompositingRegionDescendant() const
219 {
220     for (auto& region : m_regionList) {
221         if (toRenderNamedFlowFragment(region)->layerOwner().layer()->hasCompositingDescendant())
222             return true;
223     }
224
225     return false;
226 }
227
228 const RenderLayerList* RenderFlowThread::getLayerListForRegion(RenderNamedFlowFragment* region) const
229 {
230     ASSERT(m_regionToLayerListMap);
231     auto iterator = m_regionToLayerListMap->find(region);
232     return iterator == m_regionToLayerListMap->end() ? 0 : &iterator->value;
233 }
234
235 RenderNamedFlowFragment* RenderFlowThread::regionForCompositedLayer(RenderLayer& childLayer)
236 {
237     if (childLayer.renderer().fixedPositionedWithNamedFlowContainingBlock())
238         return 0;
239
240     if (childLayer.renderBox()) {
241         RenderRegion* startRegion = nullptr;
242         RenderRegion* endRegion = nullptr;
243         if (getRegionRangeForBox(childLayer.renderBox(), startRegion, endRegion))
244             return toRenderNamedFlowFragment(startRegion);
245     }
246
247     // FIXME: remove this when we'll have region ranges for inlines as well.
248     LayoutPoint flowThreadOffset = flooredLayoutPoint(childLayer.renderer().localToContainerPoint(LayoutPoint(), this, ApplyContainerFlip));
249     return toRenderNamedFlowFragment(regionAtBlockOffset(0, flipForWritingMode(isHorizontalWritingMode() ? flowThreadOffset.y() : flowThreadOffset.x()), true, DisallowRegionAutoGeneration));
250 }
251
252 RenderNamedFlowFragment* RenderFlowThread::cachedRegionForCompositedLayer(RenderLayer& childLayer) const
253 {
254     ASSERT(m_layerToRegionMap);
255     RenderNamedFlowFragment* namedFlowFragment = m_layerToRegionMap->get(&childLayer);
256     ASSERT(!namedFlowFragment || m_regionList.contains(namedFlowFragment));
257     return namedFlowFragment;
258 }
259
260 void RenderFlowThread::updateLayerToRegionMappings(RenderLayer& layer, LayerToRegionMap& layerToRegionMap, RegionToLayerListMap& regionToLayerListMap, bool& needsLayerUpdate)
261 {
262     RenderNamedFlowFragment* region = regionForCompositedLayer(layer);
263     if (!needsLayerUpdate) {
264         // Figure out if we moved this layer from a region to the other.
265         RenderNamedFlowFragment* previousRegion = cachedRegionForCompositedLayer(layer);
266         if (previousRegion != region)
267             needsLayerUpdate = true;
268     }
269
270     if (!region)
271         return;
272
273     layerToRegionMap.set(&layer, region);
274
275     auto iterator = regionToLayerListMap.find(region);
276     RenderLayerList& list = iterator == regionToLayerListMap.end() ? regionToLayerListMap.set(region, RenderLayerList()).iterator->value : iterator->value;
277     ASSERT(!list.contains(&layer));
278     list.append(&layer);
279 }
280
281 bool RenderFlowThread::updateAllLayerToRegionMappings()
282 {
283     if (!collectsGraphicsLayersUnderRegions())
284         return false;
285
286     // We can't use currentFlowThread as it is possible to have interleaved flow threads and the wrong one could be used.
287     // Let each region figure out the proper enclosing flow thread.
288     CurrentRenderFlowThreadDisabler disabler(&view());
289
290     // If the RenderFlowThread had a z-index layer update, then we need to update the composited layers too.
291     bool needsLayerUpdate = layer()->isDirtyRenderFlowThread() || m_layersToRegionMappingsDirty || !m_layerToRegionMap.get();
292     layer()->updateLayerListsIfNeeded();
293
294     LayerToRegionMap layerToRegionMap;
295     RegionToLayerListMap regionToLayerListMap;
296
297     RenderLayerList* lists[] = { layer()->negZOrderList(), layer()->normalFlowList(), layer()->posZOrderList() };
298     for (size_t listIndex = 0; listIndex < sizeof(lists) / sizeof(lists[0]); ++listIndex) {
299         if (RenderLayerList* list = lists[listIndex]) {
300             for (size_t i = 0, listSize = list->size(); i < listSize; ++i)
301                 updateLayerToRegionMappings(*list->at(i), layerToRegionMap, regionToLayerListMap, needsLayerUpdate);
302         }
303     }
304
305     if (needsLayerUpdate) {
306         if (!m_layerToRegionMap)
307             m_layerToRegionMap = std::make_unique<LayerToRegionMap>();
308         m_layerToRegionMap->swap(layerToRegionMap);
309
310         if (!m_regionToLayerListMap)
311             m_regionToLayerListMap = std::make_unique<RegionToLayerListMap>();
312         m_regionToLayerListMap->swap(regionToLayerListMap);
313     }
314
315     m_layersToRegionMappingsDirty = false;
316
317     return needsLayerUpdate;
318 }
319
320 bool RenderFlowThread::collectsGraphicsLayersUnderRegions() const
321 {
322     // We only need to map layers to regions for named flow threads.
323     // Multi-column threads are displayed on top of the regions and do not require
324     // distributing the layers.
325
326     return false;
327 }
328
329 void RenderFlowThread::updateLogicalWidth()
330 {
331     LayoutUnit logicalWidth = initialLogicalWidth();
332     for (auto& region : m_regionList) {
333         ASSERT(!region->needsLayout() || region->isRenderRegionSet());
334         logicalWidth = std::max(region->pageLogicalWidth(), logicalWidth);
335     }
336     setLogicalWidth(logicalWidth);
337
338     // If the regions have non-uniform logical widths, then insert inset information for the RenderFlowThread.
339     for (auto& region : m_regionList) {
340         LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
341         LayoutUnit logicalLeft = style().direction() == LTR ? LayoutUnit() : logicalWidth - regionLogicalWidth;
342         region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth, false);
343     }
344 }
345
346 void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
347 {
348     computedValues.m_position = logicalTop;
349     computedValues.m_extent = 0;
350
351     const LayoutUnit maxFlowSize = RenderFlowThread::maxLogicalHeight();
352     for (auto& region : m_regionList) {
353         ASSERT(!region->needsLayout() || region->isRenderRegionSet());
354
355         LayoutUnit distanceToMaxSize = maxFlowSize - computedValues.m_extent;
356         computedValues.m_extent += std::min(distanceToMaxSize, region->logicalHeightOfAllFlowThreadContent());
357
358         // If we reached the maximum size there's no point in going further.
359         if (computedValues.m_extent == maxFlowSize)
360             return;
361     }
362 }
363
364 bool RenderFlowThread::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
365 {
366     if (hitTestAction == HitTestBlockBackground)
367         return false;
368     return RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction);
369 }
370
371 bool RenderFlowThread::shouldRepaint(const LayoutRect& r) const
372 {
373     if (view().printing() || r.isEmpty())
374         return false;
375
376     return true;
377 }
378
379 void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect) const
380 {
381     if (!shouldRepaint(repaintRect) || !hasValidRegionInfo())
382         return;
383
384     LayoutStateDisabler layoutStateDisabler(&view()); // We can't use layout state to repaint, since the regions are somewhere else.
385
386     // We can't use currentFlowThread as it is possible to have interleaved flow threads and the wrong one could be used.
387     // Let each region figure out the proper enclosing flow thread.
388     CurrentRenderFlowThreadDisabler disabler(&view());
389     
390     for (auto& region : m_regionList)
391         region->repaintFlowThreadContent(repaintRect);
392 }
393
394 RenderRegion* RenderFlowThread::regionAtBlockOffset(const RenderBox* clampBox, LayoutUnit offset, bool extendLastRegion, RegionAutoGenerationPolicy autoGenerationPolicy)
395 {
396     ASSERT(!m_regionsInvalidated);
397
398     if (autoGenerationPolicy == AllowRegionAutoGeneration)
399         autoGenerateRegionsToBlockOffset(offset);
400
401     if (m_regionList.isEmpty())
402         return 0;
403
404     if (m_regionList.size() == 1 && extendLastRegion)
405         return m_regionList.first();
406
407     if (offset <= 0)
408         return clampBox ? clampBox->clampToStartAndEndRegions(m_regionList.first()) : m_regionList.first();
409
410     RegionSearchAdapter adapter(offset);
411     m_regionIntervalTree.allOverlapsWithAdapter<RegionSearchAdapter>(adapter);
412
413     // If no region was found, the offset is in the flow thread overflow.
414     // The last region will contain the offset if extendLastRegion is set or if the last region is a set.
415     if (!adapter.result() && (extendLastRegion || m_regionList.last()->isRenderRegionSet()))
416         return clampBox ? clampBox->clampToStartAndEndRegions(m_regionList.last()) : m_regionList.last();
417
418     RenderRegion* region = adapter.result();
419     if (!clampBox)
420         return region;
421     return region ? clampBox->clampToStartAndEndRegions(region) : 0;
422 }
423
424 LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint)
425 {
426     LayoutPoint referencePoint = startPoint;
427     
428     const RenderBlock* objContainingBlock = boxModelObject.containingBlock();
429     // FIXME: This needs to be adapted for different writing modes inside the flow thread.
430     RenderRegion* startRegion = regionAtBlockOffset(objContainingBlock, referencePoint.y());
431     if (startRegion) {
432         // Take into account the offset coordinates of the region.
433         RenderBoxModelObject* startRegionBox = startRegion->isRenderNamedFlowFragment() ? toRenderBoxModelObject(startRegion->parent()) : startRegion;
434         RenderBoxModelObject* currObject = startRegionBox;
435         RenderBoxModelObject* currOffsetParent;
436         while ((currOffsetParent = currObject->offsetParent())) {
437             referencePoint.move(currObject->offsetLeft(), currObject->offsetTop());
438             
439             // Since we're looking for the offset relative to the body, we must also
440             // take into consideration the borders of the region's offsetParent.
441             if (currOffsetParent->isBox() && !currOffsetParent->isBody())
442                 referencePoint.move(toRenderBox(currOffsetParent)->borderLeft(), toRenderBox(currOffsetParent)->borderTop());
443             
444             currObject = currOffsetParent;
445         }
446         
447         // We need to check if any of this box's containing blocks start in a different region
448         // and if so, drop the object's top position (which was computed relative to its containing block
449         // and is no longer valid) and recompute it using the region in which it flows as reference.
450         bool wasComputedRelativeToOtherRegion = false;
451         while (objContainingBlock && !objContainingBlock->isRenderNamedFlowThread()) {
452             // Check if this object is in a different region.
453             RenderRegion* parentStartRegion = nullptr;
454             RenderRegion* parentEndRegion = nullptr;
455             if (getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEndRegion) && parentStartRegion != startRegion) {
456                 wasComputedRelativeToOtherRegion = true;
457                 break;
458             }
459             objContainingBlock = objContainingBlock->containingBlock();
460         }
461         
462         if (wasComputedRelativeToOtherRegion) {
463             if (boxModelObject.isBox()) {
464                 // Use borderBoxRectInRegion to account for variations such as percentage margins.
465                 LayoutRect borderBoxRect = toRenderBox(boxModelObject).borderBoxRectInRegion(startRegion, RenderBox::DoNotCacheRenderBoxRegionInfo);
466                 referencePoint.move(borderBoxRect.location().x(), 0);
467             }
468             
469             // Get the logical top coordinate of the current object.
470             LayoutUnit top = 0;
471             if (boxModelObject.isRenderBlock())
472                 top = toRenderBlock(boxModelObject).offsetFromLogicalTopOfFirstPage();
473             else {
474                 if (boxModelObject.containingBlock())
475                     top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage();
476                 
477                 if (boxModelObject.isBox())
478                     top += toRenderBox(boxModelObject).topLeftLocation().y();
479                 else if (boxModelObject.isRenderInline())
480                     top -= toRenderInline(boxModelObject).borderTop();
481             }
482             
483             // Get the logical top of the region this object starts in
484             // and compute the object's top, relative to the region's top.
485             LayoutUnit regionLogicalTop = startRegion->pageLogicalTopForOffset(top);
486             LayoutUnit topRelativeToRegion = top - regionLogicalTop;
487             referencePoint.setY(startRegionBox->offsetTop() + topRelativeToRegion);
488             
489             // Since the top has been overriden, check if the
490             // relative/sticky positioning must be reconsidered.
491             if (boxModelObject.isRelPositioned())
492                 referencePoint.move(0, boxModelObject.relativePositionOffset().height());
493             else if (boxModelObject.isStickyPositioned())
494                 referencePoint.move(0, boxModelObject.stickyPositionOffset().height());
495         }
496         
497         // Since we're looking for the offset relative to the body, we must also
498         // take into consideration the borders of the region.
499         referencePoint.move(startRegionBox->borderLeft(), startRegionBox->borderTop());
500     }
501     
502     return referencePoint;
503 }
504
505 LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset)
506 {
507     RenderRegion* region = regionAtBlockOffset(0, offset, false, AllowRegionAutoGeneration);
508     return region ? region->pageLogicalTopForOffset(offset) : LayoutUnit();
509 }
510
511 LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset)
512 {
513     RenderRegion* region = regionAtBlockOffset(0, offset, true, AllowRegionAutoGeneration);
514     return region ? region->pageLogicalWidth() : contentLogicalWidth();
515 }
516
517 LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset)
518 {
519     RenderRegion* region = regionAtBlockOffset(0, offset, false, AllowRegionAutoGeneration);
520     if (!region)
521         return 0;
522
523     return region->pageLogicalHeight();
524 }
525
526 LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule)
527 {
528     RenderRegion* region = regionAtBlockOffset(0, offset, false, AllowRegionAutoGeneration);
529     if (!region)
530         return 0;
531
532     LayoutUnit pageLogicalTop = region->pageLogicalTopForOffset(offset);
533     LayoutUnit pageLogicalHeight = region->pageLogicalHeight();
534     LayoutUnit pageLogicalBottom = pageLogicalTop + pageLogicalHeight;
535     LayoutUnit remainingHeight = pageLogicalBottom - offset;
536     if (pageBoundaryRule == IncludePageBoundary) {
537         // If IncludePageBoundary is set, the line exactly on the top edge of a
538         // region will act as being part of the previous region.
539         remainingHeight = intMod(remainingHeight, pageLogicalHeight);
540     }
541     return remainingHeight;
542 }
543
544 RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformState) const
545 {
546     if (!hasValidRegionInfo())
547         return 0;
548
549     RenderRegion* renderRegion = currentRegion();
550     if (!renderRegion) {
551         LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox();
552         flipForWritingMode(boxRect);
553
554         LayoutPoint center = boxRect.center();
555         renderRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(this, isHorizontalWritingMode() ? center.y() : center.x(), true, DisallowRegionAutoGeneration);
556         if (!renderRegion)
557             return 0;
558     }
559
560     LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect());
561     flipForWritingMode(flippedRegionRect);
562
563     transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location());
564
565     return renderRegion;
566 }
567
568 void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box)
569 {
570     if (!hasRegions())
571         return;
572
573     // If the region chain was invalidated the next layout will clear the box information from all the regions.
574     if (m_regionsInvalidated) {
575         ASSERT(selfNeedsLayout());
576         return;
577     }
578
579     RenderRegion* startRegion = nullptr;
580     RenderRegion* endRegion = nullptr;
581     if (getRegionRangeForBox(box, startRegion, endRegion)) {
582         for (auto it = m_regionList.find(startRegion), end = m_regionList.end(); it != end; ++it) {
583             RenderRegion* region = *it;
584             region->removeRenderBoxRegionInfo(box);
585             if (region == endRegion)
586                 break;
587         }
588     }
589
590 #ifndef NDEBUG
591     // We have to make sure we did not leave any RenderBoxRegionInfo attached.
592     for (auto& region : m_regionList)
593         ASSERT(!region->renderBoxRegionInfo(box));
594 #endif
595
596     m_regionRangeMap.remove(box);
597 }
598
599 void RenderFlowThread::removeLineRegionInfo(const RenderBlockFlow* blockFlow)
600 {
601     if (!m_lineToRegionMap || blockFlow->m_lineLayoutPath == SimpleLinesPath)
602         return;
603
604     for (RootInlineBox* curr = blockFlow->firstRootBox(); curr; curr = curr->nextRootBox()) {
605         if (m_lineToRegionMap->contains(curr))
606             m_lineToRegionMap->remove(curr);
607     }
608
609     ASSERT_WITH_SECURITY_IMPLICATION(checkLinesConsistency(blockFlow));
610 }
611
612 void RenderFlowThread::logicalWidthChangedInRegionsForBlock(const RenderBlock* block, bool& relayoutChildren)
613 {
614     if (!hasValidRegionInfo()) {
615         // FIXME: Remove once we stop laying out flow threads without regions.
616         // If we had regions but don't any more, relayout the children because the code below
617         // can't properly detect this scenario.
618         relayoutChildren |= previousRegionCountChanged();
619         return;
620     }
621
622     auto it = m_regionRangeMap.find(block);
623     if (it == m_regionRangeMap.end())
624         return;
625
626     RenderRegionRange& range = it->value;
627     bool rangeInvalidated = range.rangeInvalidated();
628     range.clearRangeInvalidated();
629
630     // If there will be a relayout anyway skip the next steps because they only verify
631     // the state of the ranges.
632     if (relayoutChildren)
633         return;
634
635     // Not necessary for the flow thread, since we already computed the correct info for it.
636     // If the regions have changed invalidate the children.
637     if (block == this) {
638         relayoutChildren = m_pageLogicalSizeChanged;
639         return;
640     }
641
642     RenderRegion* startRegion = nullptr;
643     RenderRegion* endRegion = nullptr;
644     if (!getRegionRangeForBox(block, startRegion, endRegion))
645         return;
646
647     for (auto it = m_regionList.find(startRegion), end = m_regionList.end(); it != end; ++it) {
648         RenderRegion* region = *it;
649         ASSERT(!region->needsLayout() || region->isRenderRegionSet());
650
651         // We have no information computed for this region so we need to do it.
652         std::unique_ptr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block);
653         if (!oldInfo) {
654             relayoutChildren = rangeInvalidated;
655             return;
656         }
657
658         LayoutUnit oldLogicalWidth = oldInfo->logicalWidth();
659         RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region);
660         if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) {
661             relayoutChildren = true;
662             return;
663         }
664
665         if (region == endRegion)
666             break;
667     }
668 }
669
670 LayoutUnit RenderFlowThread::contentLogicalWidthOfFirstRegion() const
671 {
672     RenderRegion* firstValidRegionInFlow = firstRegion();
673     if (!firstValidRegionInFlow)
674         return 0;
675     return isHorizontalWritingMode() ? firstValidRegionInFlow->contentWidth() : firstValidRegionInFlow->contentHeight();
676 }
677
678 LayoutUnit RenderFlowThread::contentLogicalHeightOfFirstRegion() const
679 {
680     RenderRegion* firstValidRegionInFlow = firstRegion();
681     if (!firstValidRegionInFlow)
682         return 0;
683     return isHorizontalWritingMode() ? firstValidRegionInFlow->contentHeight() : firstValidRegionInFlow->contentWidth();
684 }
685
686 LayoutUnit RenderFlowThread::contentLogicalLeftOfFirstRegion() const
687 {
688     RenderRegion* firstValidRegionInFlow = firstRegion();
689     if (!firstValidRegionInFlow)
690         return 0;
691     return isHorizontalWritingMode() ? firstValidRegionInFlow->flowThreadPortionRect().x() : firstValidRegionInFlow->flowThreadPortionRect().y();
692 }
693
694 RenderRegion* RenderFlowThread::firstRegion() const
695 {
696     if (!hasRegions())
697         return 0;
698     return m_regionList.first();
699 }
700
701 RenderRegion* RenderFlowThread::lastRegion() const
702 {
703     if (!hasRegions())
704         return 0;
705     return m_regionList.last();
706 }
707
708 void RenderFlowThread::clearRenderBoxRegionInfoAndCustomStyle(const RenderBox* box,
709     const RenderRegion* newStartRegion, const RenderRegion* newEndRegion,
710     const RenderRegion* oldStartRegion, const RenderRegion* oldEndRegion)
711 {
712     ASSERT(newStartRegion && newEndRegion && oldStartRegion && oldEndRegion);
713
714     bool insideOldRegionRange = false;
715     bool insideNewRegionRange = false;
716     for (auto& region : m_regionList) {
717         if (oldStartRegion == region)
718             insideOldRegionRange = true;
719         if (newStartRegion == region)
720             insideNewRegionRange = true;
721
722         if (!(insideOldRegionRange && insideNewRegionRange)) {
723             if (region->isRenderNamedFlowFragment())
724                 toRenderNamedFlowFragment(region)->clearObjectStyleInRegion(box);
725             if (region->renderBoxRegionInfo(box))
726                 region->removeRenderBoxRegionInfo(box);
727         }
728
729         if (oldEndRegion == region)
730             insideOldRegionRange = false;
731         if (newEndRegion == region)
732             insideNewRegionRange = false;
733     }
734 }
735
736 void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, RenderRegion* startRegion, RenderRegion* endRegion)
737 {
738     ASSERT(hasRegions());
739     ASSERT(startRegion && endRegion && startRegion->flowThread() == this && endRegion->flowThread() == this);
740
741     auto it = m_regionRangeMap.find(box);
742     if (it == m_regionRangeMap.end()) {
743         m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion));
744         return;
745     }
746
747     // If nothing changed, just bail.
748     RenderRegionRange& range = it->value;
749     if (range.startRegion() == startRegion && range.endRegion() == endRegion)
750         return;
751
752     clearRenderBoxRegionInfoAndCustomStyle(box, startRegion, endRegion, range.startRegion(), range.endRegion());
753     range.setRange(startRegion, endRegion);
754 }
755
756 bool RenderFlowThread::hasCachedRegionRangeForBox(const RenderBox* box) const
757 {
758     ASSERT(box);
759
760     return m_regionRangeMap.contains(box);
761 }
762
763 bool RenderFlowThread::getRegionRangeForBoxFromCachedInfo(const RenderBox* box, RenderRegion*& startRegion, RenderRegion*& endRegion) const
764 {
765     ASSERT(box);
766     ASSERT(hasValidRegionInfo());
767     ASSERT((startRegion == nullptr) && (endRegion == nullptr));
768
769     auto it = m_regionRangeMap.find(box);
770     if (it != m_regionRangeMap.end()) {
771         const RenderRegionRange& range = it->value;
772         startRegion = range.startRegion();
773         endRegion = range.endRegion();
774         ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion));
775         return true;
776     }
777
778     return false;
779 }
780
781 bool RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*& startRegion, RenderRegion*& endRegion) const
782 {
783     ASSERT(box);
784
785     startRegion = endRegion = nullptr;
786     if (!hasValidRegionInfo()) // We clear the ranges when we invalidate the regions.
787         return false;
788
789     if (m_regionList.size() == 1) {
790         startRegion = endRegion = m_regionList.first();
791         return true;
792     }
793
794     if (getRegionRangeForBoxFromCachedInfo(box, startRegion, endRegion))
795         return true;
796
797     return false;
798 }
799
800 bool RenderFlowThread::computedRegionRangeForBox(const RenderBox* box, RenderRegion*& startRegion, RenderRegion*& endRegion) const
801 {
802     ASSERT(box);
803
804     startRegion = endRegion = nullptr;
805     if (!hasValidRegionInfo()) // We clear the ranges when we invalidate the regions.
806         return false;
807
808     if (getRegionRangeForBox(box, startRegion, endRegion))
809         return true;
810
811     // Search the region range using the information provided by the
812     // containing block chain.
813     RenderBox* cb = const_cast<RenderBox*>(box);
814     while (!cb->isRenderFlowThread()) {
815         InlineElementBox* boxWrapper = cb->inlineBoxWrapper();
816         if (boxWrapper && boxWrapper->root().containingRegion()) {
817             startRegion = endRegion = boxWrapper->root().containingRegion();
818             ASSERT(m_regionList.contains(startRegion));
819             return true;
820         }
821
822         // FIXME: Use the containingBlock() value once we patch all the layout systems to be region range aware
823         // (e.g. if we use containingBlock() the shadow controls of a video element won't get the range from the
824         // video box because it's not a block; they need to be patched separately).
825         ASSERT(cb->parent());
826         cb = &cb->parent()->enclosingBox();
827         ASSERT(cb);
828
829         // If a box doesn't have a cached region range it usually means the box belongs to a line so startRegion should be equal with endRegion.
830         // FIXME: Find the cases when this startRegion should not be equal with endRegion and make sure these boxes have cached region ranges.
831         if (hasCachedRegionRangeForBox(cb)) {
832             startRegion = endRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(cb, box->offsetFromLogicalTopOfFirstPage(), true, DisallowRegionAutoGeneration);
833             return true;
834         }
835     }
836
837     ASSERT_NOT_REACHED();
838     return false;
839 }
840
841 bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const
842 {
843     ASSERT(targetRegion);
844
845     for (auto it = m_regionList.find(const_cast<RenderRegion*>(startRegion)), end = m_regionList.end(); it != end; ++it) {
846         const RenderRegion* currRegion = *it;
847         if (targetRegion == currRegion)
848             return true;
849         if (currRegion == endRegion)
850             break;
851     }
852
853     return false;
854 }
855
856 bool RenderFlowThread::objectShouldFragmentInFlowRegion(const RenderObject* object, const RenderRegion* region) const
857 {
858     ASSERT(object);
859     ASSERT(region);
860     
861     RenderFlowThread* flowThread = object->flowThreadContainingBlock();
862     if (flowThread != this)
863         return false;
864
865     if (!m_regionList.contains(const_cast<RenderRegion*>(region)))
866         return false;
867     
868     RenderRegion* enclosingBoxStartRegion = nullptr;
869     RenderRegion* enclosingBoxEndRegion = nullptr;
870     // If the box has no range, do not check regionInRange. Boxes inside inlines do not get ranges.
871     // Instead, the containing RootInlineBox will abort when trying to paint inside the wrong region.
872     if (computedRegionRangeForBox(&object->enclosingBox(), enclosingBoxStartRegion, enclosingBoxEndRegion)
873         && !regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion))
874         return false;
875     
876     return object->isBox() || object->isRenderInline();
877 }
878
879 bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const RenderRegion* region) const
880 {
881     ASSERT(object);
882     ASSERT(region);
883
884     RenderFlowThread* flowThread = object->flowThreadContainingBlock();
885     if (flowThread != this)
886         return false;
887
888     if (!m_regionList.contains(const_cast<RenderRegion*>(region)))
889         return false;
890
891     RenderRegion* enclosingBoxStartRegion = nullptr;
892     RenderRegion* enclosingBoxEndRegion = nullptr;
893     if (!getRegionRangeForBox(&object->enclosingBox(), enclosingBoxStartRegion, enclosingBoxEndRegion))
894         return false;
895
896     if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion))
897         return false;
898
899     if (object->isBox())
900         return true;
901
902     LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true);
903     if (!objectABBRect.width())
904         objectABBRect.setWidth(1);
905     if (!objectABBRect.height())
906         objectABBRect.setHeight(1); 
907     if (objectABBRect.intersects(region->absoluteBoundingBoxRect(true)))
908         return true;
909
910     if (region == lastRegion()) {
911         // If the object does not intersect any of the enclosing box regions
912         // then the object is in last region.
913         for (auto it = m_regionList.find(enclosingBoxStartRegion), end = m_regionList.end(); it != end; ++it) {
914             const RenderRegion* currRegion = *it;
915             if (currRegion == region)
916                 break;
917             if (objectABBRect.intersects(currRegion->absoluteBoundingBoxRect(true)))
918                 return false;
919         }
920         return true;
921     }
922
923     return false;
924 }
925
926 #ifndef NDEBUG
927 bool RenderFlowThread::isAutoLogicalHeightRegionsCountConsistent() const
928 {
929     unsigned autoLogicalHeightRegions = 0;
930     for (const auto& region : m_regionList) {
931         if (region->hasAutoLogicalHeight())
932             autoLogicalHeightRegions++;
933     }
934
935     return autoLogicalHeightRegions == m_autoLogicalHeightRegionsCount;
936 }
937 #endif
938
939 #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
940 bool RenderFlowThread::checkLinesConsistency(const RenderBlockFlow* removedBlock) const
941 {
942     if (!m_lineToRegionMap)
943         return true;
944
945     for (auto& linePair : *m_lineToRegionMap.get()) {
946         const RootInlineBox* line = linePair.key;
947         RenderRegion* region = linePair.value;
948         if (&line->blockFlow() == removedBlock)
949             return false;
950         if (line->blockFlow().flowThreadState() == NotInsideFlowThread)
951             return false;
952         if (!m_regionList.contains(region))
953             return false;
954     }
955
956     return true;
957 }
958 #endif
959
960 void RenderFlowThread::clearLinesToRegionMap()
961 {
962     if (m_lineToRegionMap)
963         m_lineToRegionMap->clear();
964 }
965
966 void RenderFlowThread::deleteLines()
967 {
968     clearLinesToRegionMap();
969     RenderBlockFlow::deleteLines();
970 }
971
972 void RenderFlowThread::willBeDestroyed()
973 {
974     clearLinesToRegionMap();
975     RenderBlockFlow::willBeDestroyed();
976 }
977
978 // During the measure content layout phase of the named flow the regions are initialized with a height equal to their max-height.
979 // This way unforced breaks are automatically placed when a region is full and the content height/position correctly estimated.
980 // Also, the region where a forced break falls is exactly the region found at the forced break offset inside the flow content.
981 void RenderFlowThread::initializeRegionsComputedAutoHeight(RenderRegion* startRegion)
982 {
983     ASSERT(inMeasureContentLayoutPhase());
984     if (!hasAutoLogicalHeightRegions())
985         return;
986
987     for (auto regionIter = startRegion ? m_regionList.find(startRegion) : m_regionList.begin(), end = m_regionList.end(); regionIter != end; ++regionIter) {
988         RenderRegion* region = *regionIter;
989         if (region->hasAutoLogicalHeight()) {
990             RenderNamedFlowFragment* namedFlowFragment = toRenderNamedFlowFragment(region);
991             namedFlowFragment->setComputedAutoHeight(namedFlowFragment->maxPageLogicalHeight());
992         }
993     }
994 }
995
996 void RenderFlowThread::markAutoLogicalHeightRegionsForLayout()
997 {
998     ASSERT(hasAutoLogicalHeightRegions());
999
1000     for (auto& region : m_regionList) {
1001         if (!region->hasAutoLogicalHeight())
1002             continue;
1003
1004         // FIXME: We need to find a way to avoid marking all the regions ancestors for layout
1005         // as we are already inside layout.
1006         region->setNeedsLayout();
1007     }
1008 }
1009
1010 void RenderFlowThread::markRegionsForOverflowLayoutIfNeeded()
1011 {
1012     if (!hasRegions())
1013         return;
1014
1015     for (auto& region : m_regionList)
1016         region->setNeedsSimplifiedNormalFlowLayout();
1017 }
1018
1019 void RenderFlowThread::updateRegionsFlowThreadPortionRect(const RenderRegion* lastRegionWithContent)
1020 {
1021     ASSERT(!lastRegionWithContent || (inMeasureContentLayoutPhase() && hasAutoLogicalHeightRegions()));
1022     LayoutUnit logicalHeight = 0;
1023     bool emptyRegionsSegment = false;
1024     // FIXME: Optimize not to clear the interval all the time. This implies manually managing the tree nodes lifecycle.
1025     m_regionIntervalTree.clear();
1026     m_regionIntervalTree.initIfNeeded();
1027     for (auto& region : m_regionList) {
1028         // If we find an empty auto-height region, clear the computedAutoHeight value.
1029         if (emptyRegionsSegment && region->hasAutoLogicalHeight())
1030             toRenderNamedFlowFragment(region)->clearComputedAutoHeight();
1031
1032         LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
1033         LayoutUnit regionLogicalHeight = std::min<LayoutUnit>(RenderFlowThread::maxLogicalHeight() - logicalHeight, region->logicalHeightOfAllFlowThreadContent());
1034
1035         LayoutRect regionRect(style().direction() == LTR ? LayoutUnit() : logicalWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogicalHeight);
1036
1037         region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect());
1038
1039         m_regionIntervalTree.add(RegionIntervalTree::createInterval(logicalHeight, logicalHeight + regionLogicalHeight, region));
1040
1041         logicalHeight += regionLogicalHeight;
1042
1043         // Once we find the last region with content the next regions are considered empty.
1044         if (lastRegionWithContent == region)
1045             emptyRegionsSegment = true;
1046     }
1047
1048     ASSERT(!lastRegionWithContent || emptyRegionsSegment);
1049 }
1050
1051 // Even if we require the break to occur at offsetBreakInFlowThread, because regions may have min/max-height values,
1052 // it is possible that the break will occur at a different offset than the original one required.
1053 // offsetBreakAdjustment measures the different between the requested break offset and the current break offset.
1054 bool RenderFlowThread::addForcedRegionBreak(const RenderBlock* block, LayoutUnit offsetBreakInFlowThread, RenderBox* breakChild, bool isBefore, LayoutUnit* offsetBreakAdjustment)
1055 {
1056     // We take breaks into account for height computation for auto logical height regions
1057     // only in the layout phase in which we lay out the flows threads unconstrained
1058     // and we use the content breaks to determine the computed auto height for
1059     // auto logical height regions.
1060     if (!inMeasureContentLayoutPhase())
1061         return false;
1062
1063     // Breaks can come before or after some objects. We need to track these objects, so that if we get
1064     // multiple breaks for the same object (for example because of multiple layouts on the same object),
1065     // we need to invalidate every other region after the old one and start computing from fresh.
1066     RenderBoxToRegionMap& mapToUse = isBefore ? m_breakBeforeToRegionMap : m_breakAfterToRegionMap;
1067     auto iter = mapToUse.find(breakChild);
1068     if (iter != mapToUse.end()) {
1069         auto regionIter = m_regionList.find(iter->value);
1070         ASSERT(regionIter != m_regionList.end());
1071         ASSERT((*regionIter)->hasAutoLogicalHeight());
1072         initializeRegionsComputedAutoHeight(*regionIter);
1073
1074         // We need to update the regions flow thread portion rect because we are going to process
1075         // a break on these regions.
1076         updateRegionsFlowThreadPortionRect();
1077     }
1078
1079     // Simulate a region break at offsetBreakInFlowThread. If it points inside an auto logical height region,
1080     // then it determines the region computed auto height.
1081     RenderRegion* region = regionAtBlockOffset(block, offsetBreakInFlowThread);
1082     if (!region)
1083         return false;
1084
1085     bool lastBreakAfterContent = breakChild == this;
1086     bool hasComputedAutoHeight = false;
1087
1088     LayoutUnit currentRegionOffsetInFlowThread = isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x();
1089     LayoutUnit offsetBreakInCurrentRegion = offsetBreakInFlowThread - currentRegionOffsetInFlowThread;
1090
1091     if (region->hasAutoLogicalHeight()) {
1092         RenderNamedFlowFragment* namedFlowFragment = toRenderNamedFlowFragment(region);
1093
1094         // A forced break can appear only in an auto-height region that didn't have a forced break before.
1095         // This ASSERT is a good-enough heuristic to verify the above condition.
1096         ASSERT(namedFlowFragment->maxPageLogicalHeight() == namedFlowFragment->computedAutoHeight());
1097
1098         mapToUse.set(breakChild, namedFlowFragment);
1099
1100         hasComputedAutoHeight = true;
1101
1102         // Compute the region height pretending that the offsetBreakInCurrentRegion is the logicalHeight for the auto-height region.
1103         LayoutUnit regionComputedAutoHeight = namedFlowFragment->constrainContentBoxLogicalHeightByMinMax(offsetBreakInCurrentRegion);
1104
1105         // The new height of this region needs to be smaller than the initial value, the max height. A forced break is the only way to change the initial
1106         // height of an auto-height region besides content ending.
1107         ASSERT(regionComputedAutoHeight <= namedFlowFragment->maxPageLogicalHeight());
1108
1109         namedFlowFragment->setComputedAutoHeight(regionComputedAutoHeight);
1110
1111         currentRegionOffsetInFlowThread += regionComputedAutoHeight;
1112     } else
1113         currentRegionOffsetInFlowThread += isHorizontalWritingMode() ? region->flowThreadPortionRect().height() : region->flowThreadPortionRect().width();
1114
1115     // If the break was found inside an auto-height region its size changed so we need to recompute the flow thread portion rectangles.
1116     // Also, if this is the last break after the content we need to clear the computedAutoHeight value on the last empty regions.
1117     if (hasAutoLogicalHeightRegions() && lastBreakAfterContent)
1118         updateRegionsFlowThreadPortionRect(region);
1119     else if (hasComputedAutoHeight)
1120         updateRegionsFlowThreadPortionRect();
1121
1122     if (offsetBreakAdjustment)
1123         *offsetBreakAdjustment = std::max<LayoutUnit>(0, currentRegionOffsetInFlowThread - offsetBreakInFlowThread);
1124
1125     return hasComputedAutoHeight;
1126 }
1127
1128 void RenderFlowThread::incrementAutoLogicalHeightRegions()
1129 {
1130     if (!m_autoLogicalHeightRegionsCount)
1131         view().flowThreadController().incrementFlowThreadsWithAutoLogicalHeightRegions();
1132     ++m_autoLogicalHeightRegionsCount;
1133 }
1134
1135 void RenderFlowThread::decrementAutoLogicalHeightRegions()
1136 {
1137     ASSERT(m_autoLogicalHeightRegionsCount > 0);
1138     --m_autoLogicalHeightRegionsCount;
1139     if (!m_autoLogicalHeightRegionsCount)
1140         view().flowThreadController().decrementFlowThreadsWithAutoLogicalHeightRegions();
1141 }
1142
1143 void RenderFlowThread::collectLayerFragments(LayerFragments& layerFragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
1144 {
1145     ASSERT(!m_regionsInvalidated);
1146     
1147     for (auto& region : m_regionList)
1148         region->collectLayerFragments(layerFragments, layerBoundingBox, dirtyRect);
1149 }
1150
1151 LayoutRect RenderFlowThread::fragmentsBoundingBox(const LayoutRect& layerBoundingBox)
1152 {
1153     ASSERT(!m_regionsInvalidated);
1154     
1155     LayoutRect result;
1156     for (auto& region : m_regionList) {
1157         LayerFragments fragments;
1158         region->collectLayerFragments(fragments, layerBoundingBox, LayoutRect::infiniteRect());
1159         for (const auto& fragment : fragments) {
1160             LayoutRect fragmentRect(layerBoundingBox);
1161             fragmentRect.intersect(fragment.paginationClip);
1162             fragmentRect.move(fragment.paginationOffset);
1163             result.unite(fragmentRect);
1164         }
1165     }
1166     
1167     return result;
1168 }
1169
1170 bool RenderFlowThread::hasCachedOffsetFromLogicalTopOfFirstRegion(const RenderBox* box) const
1171 {
1172     return m_boxesToOffsetMap.contains(box);
1173 }
1174
1175 LayoutUnit RenderFlowThread::cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox* box) const
1176 {
1177     return m_boxesToOffsetMap.get(box);
1178 }
1179
1180 void RenderFlowThread::setOffsetFromLogicalTopOfFirstRegion(const RenderBox* box, LayoutUnit offset)
1181 {
1182     m_boxesToOffsetMap.set(box, offset);
1183 }
1184
1185 void RenderFlowThread::clearOffsetFromLogicalTopOfFirstRegion(const RenderBox* box)
1186 {
1187     ASSERT(m_boxesToOffsetMap.contains(box));
1188     m_boxesToOffsetMap.remove(box);
1189 }
1190
1191 const RenderBox* RenderFlowThread::currentActiveRenderBox() const
1192 {
1193     if (m_activeObjectsStack.isEmpty())
1194         return 0;
1195
1196     const RenderObject* currentObject = m_activeObjectsStack.last();
1197     return currentObject->isBox() ? toRenderBox(currentObject) : 0;
1198 }
1199
1200 void RenderFlowThread::pushFlowThreadLayoutState(const RenderObject& object)
1201 {
1202     m_activeObjectsStack.add(&object);
1203
1204     if (const RenderBox* currentBoxDescendant = currentActiveRenderBox()) {
1205         LayoutState* layoutState = currentBoxDescendant->view().layoutState();
1206         if (layoutState && layoutState->isPaginated()) {
1207             ASSERT(layoutState->m_renderer == currentBoxDescendant);
1208             LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
1209             setOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant, currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width());
1210         }
1211     }
1212 }
1213
1214 void RenderFlowThread::popFlowThreadLayoutState()
1215 {
1216     if (const RenderBox* currentBoxDescendant = currentActiveRenderBox()) {
1217         LayoutState* layoutState = currentBoxDescendant->view().layoutState();
1218         if (layoutState && layoutState->isPaginated())
1219             clearOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant);
1220     }
1221
1222     m_activeObjectsStack.removeLast();
1223 }
1224
1225 LayoutUnit RenderFlowThread::offsetFromLogicalTopOfFirstRegion(const RenderBlock* currentBlock) const
1226 {
1227     // First check if we cached the offset for the block if it's an ancestor containing block of the box
1228     // being currently laid out.
1229     if (hasCachedOffsetFromLogicalTopOfFirstRegion(currentBlock))
1230         return cachedOffsetFromLogicalTopOfFirstRegion(currentBlock);
1231
1232     // As a last resort, take the slow path.
1233     LayoutRect blockRect(0, 0, currentBlock->width(), currentBlock->height());
1234     while (currentBlock && !currentBlock->isRenderFlowThread()) {
1235         RenderBlock* containerBlock = currentBlock->containingBlock();
1236         ASSERT(containerBlock);
1237         if (!containerBlock)
1238             return 0;
1239         LayoutPoint currentBlockLocation = currentBlock->location();
1240
1241         if (containerBlock->style().writingMode() != currentBlock->style().writingMode()) {
1242             // We have to put the block rect in container coordinates
1243             // and we have to take into account both the container and current block flipping modes
1244             if (containerBlock->style().isFlippedBlocksWritingMode()) {
1245                 if (containerBlock->isHorizontalWritingMode())
1246                     blockRect.setY(currentBlock->height() - blockRect.maxY());
1247                 else
1248                     blockRect.setX(currentBlock->width() - blockRect.maxX());
1249             }
1250             currentBlock->flipForWritingMode(blockRect);
1251         }
1252         blockRect.moveBy(currentBlockLocation);
1253         currentBlock = containerBlock;
1254     }
1255
1256     return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
1257 }
1258
1259 void RenderFlowThread::RegionSearchAdapter::collectIfNeeded(const RegionInterval& interval)
1260 {
1261     if (m_result)
1262         return;
1263     if (interval.low() <= m_offset && interval.high() > m_offset)
1264         m_result = interval.data();
1265 }
1266
1267 void RenderFlowThread::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1268 {
1269     if (this == repaintContainer)
1270         return;
1271
1272     if (RenderRegion* region = mapFromFlowToRegion(transformState)) {
1273         // FIXME: The cast below is probably not the best solution, we may need to find a better way.
1274         const RenderObject* regionObject = static_cast<const RenderObject*>(region);
1275
1276         // If the repaint container is nullptr, we have to climb up to the RenderView, otherwise swap
1277         // it with the region's repaint container.
1278         repaintContainer = repaintContainer ? region->containerForRepaint() : nullptr;
1279
1280         if (RenderFlowThread* regionFlowThread = region->flowThreadContainingBlock()) {
1281             RenderRegion* startRegion = nullptr;
1282             RenderRegion* endRegion = nullptr;
1283             if (regionFlowThread->getRegionRangeForBox(region, startRegion, endRegion)) {
1284                 CurrentRenderRegionMaintainer regionMaintainer(*startRegion);
1285                 regionObject->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1286                 return;
1287             }
1288         }
1289
1290         regionObject->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
1291     }
1292 }
1293
1294 // FIXME: Make this function faster. Walking the render tree is slow, better use a caching mechanism (e.g. |cachedOffsetFromLogicalTopOfFirstRegion|).
1295 LayoutRect RenderFlowThread::mapFromLocalToFlowThread(const RenderBox* box, const LayoutRect& localRect) const
1296 {
1297     LayoutRect boxRect = localRect;
1298
1299     while (box && box != this) {
1300         RenderBlock* containerBlock = box->containingBlock();
1301         ASSERT(containerBlock);
1302         if (!containerBlock)
1303             return LayoutRect();
1304         LayoutPoint currentBoxLocation = box->location();
1305
1306         if (containerBlock->style().writingMode() != box->style().writingMode())
1307             box->flipForWritingMode(boxRect);
1308
1309         boxRect.moveBy(currentBoxLocation);
1310         box = containerBlock;
1311     }
1312
1313     return boxRect;
1314 }
1315
1316 // FIXME: Make this function faster. Walking the render tree is slow, better use a caching mechanism (e.g. |cachedOffsetFromLogicalTopOfFirstRegion|).
1317 LayoutRect RenderFlowThread::mapFromFlowThreadToLocal(const RenderBox* box, const LayoutRect& rect) const
1318 {
1319     LayoutRect localRect = rect;
1320     if (box == this)
1321         return localRect;
1322
1323     RenderBlock* containerBlock = box->containingBlock();
1324     ASSERT(containerBlock);
1325     if (!containerBlock)
1326         return LayoutRect();
1327     localRect = mapFromFlowThreadToLocal(containerBlock, localRect);
1328
1329     LayoutPoint currentBoxLocation = box->location();
1330     localRect.moveBy(-currentBoxLocation);
1331
1332     if (containerBlock->style().writingMode() != box->style().writingMode())
1333         box->flipForWritingMode(localRect);
1334
1335     return localRect;
1336 }
1337
1338 void RenderFlowThread::flipForWritingModeLocalCoordinates(LayoutRect& rect) const
1339 {
1340     if (!style().isFlippedBlocksWritingMode())
1341         return;
1342     
1343     if (isHorizontalWritingMode())
1344         rect.setY(0 - rect.maxY());
1345     else
1346         rect.setX(0 - rect.maxX());
1347 }
1348
1349 void RenderFlowThread::addRegionsVisualEffectOverflow(const RenderBox* box)
1350 {
1351     RenderRegion* startRegion = nullptr;
1352     RenderRegion* endRegion = nullptr;
1353     if (!getRegionRangeForBox(box, startRegion, endRegion))
1354         return;
1355
1356     for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
1357         RenderRegion* region = *iter;
1358
1359         LayoutRect borderBox = box->borderBoxRectInRegion(region);
1360         borderBox = box->applyVisualEffectOverflow(borderBox);
1361         borderBox = region->rectFlowPortionForBox(box, borderBox);
1362
1363         region->addVisualOverflowForBox(box, borderBox);
1364         if (region == endRegion)
1365             break;
1366     }
1367 }
1368
1369 void RenderFlowThread::addRegionsVisualOverflowFromTheme(const RenderBlock* block)
1370 {
1371     RenderRegion* startRegion = nullptr;
1372     RenderRegion* endRegion = nullptr;
1373     if (!getRegionRangeForBox(block, startRegion, endRegion))
1374         return;
1375
1376     for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
1377         RenderRegion* region = *iter;
1378
1379         LayoutRect borderBox = block->borderBoxRectInRegion(region);
1380         borderBox = region->rectFlowPortionForBox(block, borderBox);
1381
1382         FloatRect inflatedRect = borderBox;
1383         block->theme().adjustRepaintRect(*block, inflatedRect);
1384
1385         region->addVisualOverflowForBox(block, pixelSnappedIntRect(LayoutRect(inflatedRect)));
1386         if (region == endRegion)
1387             break;
1388     }
1389 }
1390
1391 void RenderFlowThread::addRegionsOverflowFromChild(const RenderBox* box, const RenderBox* child, const LayoutSize& delta)
1392 {
1393     RenderRegion* startRegion = nullptr;
1394     RenderRegion* endRegion = nullptr;
1395     if (!getRegionRangeForBox(child, startRegion, endRegion))
1396         return;
1397
1398     RenderRegion* containerStartRegion = nullptr;
1399     RenderRegion* containerEndRegion = nullptr;
1400     if (!getRegionRangeForBox(box, containerStartRegion, containerEndRegion))
1401         return;
1402
1403     for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
1404         RenderRegion* region = *iter;
1405         if (!regionInRange(region, containerStartRegion, containerEndRegion)) {
1406             if (region == endRegion)
1407                 break;
1408             continue;
1409         }
1410
1411         LayoutRect childLayoutOverflowRect = region->layoutOverflowRectForBoxForPropagation(child);
1412         childLayoutOverflowRect.move(delta);
1413         
1414         // When propagating the layout overflow to the flow thread object, make sure to include
1415         // the logical bottom padding of the scrollable region and the bottom margin of the flowed element.
1416         // In order to behave in a similar manner to the non-regions case, content overflowing the box
1417         // flowed into the region must be painted on top of the region's padding and the box's margin.
1418         // See http://lists.w3.org/Archives/Public/www-style/2014Jan/0089.html
1419         if (box->isRenderNamedFlowThread()) {
1420             ASSERT(box == this);
1421             RenderBlockFlow& fragmentContainer = toRenderNamedFlowFragment(region)->fragmentContainer();
1422             LayoutUnit spacingAfterLayout = fragmentContainer.paddingAfter() + child->marginAfter();
1423             if (isHorizontalWritingMode()) {
1424                 if (fragmentContainer.scrollsOverflowY()) {
1425                     LayoutUnit layoutMaxLogicalY = region->rectFlowPortionForBox(child, child->frameRect()).maxY() + spacingAfterLayout;
1426                     LayoutUnit maxYDiff = layoutMaxLogicalY - childLayoutOverflowRect.maxY();
1427                     if (maxYDiff > 0)
1428                         childLayoutOverflowRect.expand(0, maxYDiff);
1429                 }
1430             } else {
1431                 if (fragmentContainer.scrollsOverflowX()) {
1432                     LayoutUnit layoutMaxLogicalY = region->rectFlowPortionForBox(child, child->frameRect()).maxX() + spacingAfterLayout;
1433                     LayoutUnit maxYDiff = layoutMaxLogicalY - childLayoutOverflowRect.maxX();
1434                     if (maxYDiff > 0)
1435                         childLayoutOverflowRect.expand(maxYDiff, 0);
1436                 }
1437             }
1438         }
1439         
1440         region->addLayoutOverflowForBox(box, childLayoutOverflowRect);
1441
1442         if (child->hasSelfPaintingLayer() || box->hasOverflowClip()) {
1443             if (region == endRegion)
1444                 break;
1445             continue;
1446         }
1447         LayoutRect childVisualOverflowRect = region->visualOverflowRectForBoxForPropagation(child);
1448         childVisualOverflowRect.move(delta);
1449         region->addVisualOverflowForBox(box, childVisualOverflowRect);
1450
1451         if (region == endRegion)
1452             break;
1453     }
1454 }
1455     
1456 void RenderFlowThread::addRegionsLayoutOverflow(const RenderBox* box, const LayoutRect& layoutOverflow)
1457 {
1458     RenderRegion* startRegion = nullptr;
1459     RenderRegion* endRegion = nullptr;
1460     if (!getRegionRangeForBox(box, startRegion, endRegion))
1461         return;
1462
1463     for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
1464         RenderRegion* region = *iter;
1465         LayoutRect layoutOverflowInRegion = region->rectFlowPortionForBox(box, layoutOverflow);
1466
1467         region->addLayoutOverflowForBox(box, layoutOverflowInRegion);
1468
1469         if (region == endRegion)
1470             break;
1471     }
1472 }
1473
1474 void RenderFlowThread::addRegionsVisualOverflow(const RenderBox* box, const LayoutRect& visualOverflow)
1475 {
1476     RenderRegion* startRegion = nullptr;
1477     RenderRegion* endRegion = nullptr;
1478     if (!getRegionRangeForBox(box, startRegion, endRegion))
1479         return;
1480     
1481     for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) {
1482         RenderRegion* region = *iter;
1483         LayoutRect visualOverflowInRegion = region->rectFlowPortionForBox(box, visualOverflow);
1484         
1485         region->addVisualOverflowForBox(box, visualOverflowInRegion);
1486         
1487         if (region == endRegion)
1488             break;
1489     }
1490 }
1491
1492 void RenderFlowThread::clearRegionsOverflow(const RenderBox* box)
1493 {
1494     RenderRegion* startRegion = nullptr;
1495     RenderRegion* endRegion = nullptr;
1496     if (!getRegionRangeForBox(box, startRegion, endRegion))
1497         return;
1498
1499     for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
1500         RenderRegion* region = *iter;
1501         RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(box);
1502         if (boxInfo && boxInfo->overflow())
1503             boxInfo->clearOverflow();
1504
1505         if (region == endRegion)
1506             break;
1507     }
1508 }
1509
1510 RenderRegion* RenderFlowThread::currentRegion() const
1511 {
1512     return m_currentRegionMaintainer ? &m_currentRegionMaintainer->region() : nullptr;
1513 }
1514
1515 ContainingRegionMap& RenderFlowThread::containingRegionMap()
1516 {
1517     if (!m_lineToRegionMap)
1518         m_lineToRegionMap = std::make_unique<ContainingRegionMap>();
1519
1520     return *m_lineToRegionMap.get();
1521 }
1522
1523 CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowThread* renderFlowThread)
1524     : m_renderFlowThread(renderFlowThread)
1525     , m_previousRenderFlowThread(0)
1526 {
1527     if (!m_renderFlowThread)
1528         return;
1529     FlowThreadController& controller = m_renderFlowThread->view().flowThreadController();
1530     m_previousRenderFlowThread = controller.currentRenderFlowThread();
1531     // Remove the assert so we can use this to change the flow thread context.
1532     // ASSERT(!m_previousRenderFlowThread || !renderFlowThread->isRenderNamedFlowThread());
1533     controller.setCurrentRenderFlowThread(m_renderFlowThread);
1534 }
1535
1536 CurrentRenderFlowThreadMaintainer::~CurrentRenderFlowThreadMaintainer()
1537 {
1538     if (!m_renderFlowThread)
1539         return;
1540     FlowThreadController& controller = m_renderFlowThread->view().flowThreadController();
1541     ASSERT(controller.currentRenderFlowThread() == m_renderFlowThread);
1542     controller.setCurrentRenderFlowThread(m_previousRenderFlowThread);
1543 }
1544
1545 CurrentRenderFlowThreadDisabler::CurrentRenderFlowThreadDisabler(RenderView* view)
1546     : m_view(view)
1547     , m_renderFlowThread(0)
1548 {
1549     m_renderFlowThread = m_view->flowThreadController().currentRenderFlowThread();
1550     if (m_renderFlowThread)
1551         view->flowThreadController().setCurrentRenderFlowThread(0);
1552 }
1553
1554 CurrentRenderFlowThreadDisabler::~CurrentRenderFlowThreadDisabler()
1555 {
1556     if (m_renderFlowThread)
1557         m_view->flowThreadController().setCurrentRenderFlowThread(m_renderFlowThread);
1558 }
1559
1560
1561 } // namespace WebCore