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