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