Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/rendering/RenderFlowThread.h"
33
34 #include "core/dom/Node.h"
35 #include "core/rendering/FlowThreadController.h"
36 #include "core/rendering/HitTestRequest.h"
37 #include "core/rendering/HitTestResult.h"
38 #include "core/rendering/LayoutRectRecorder.h"
39 #include "core/rendering/PaintInfo.h"
40 #include "core/rendering/RenderInline.h"
41 #include "core/rendering/RenderLayer.h"
42 #include "core/rendering/RenderRegion.h"
43 #include "core/rendering/RenderView.h"
44 #include "platform/PODIntervalTree.h"
45 #include "platform/geometry/TransformState.h"
46
47 namespace WebCore {
48
49 RenderFlowThread::RenderFlowThread()
50     : RenderBlockFlow(0)
51     , m_previousRegionCount(0)
52     , m_regionsInvalidated(false)
53     , m_regionsHaveUniformLogicalHeight(true)
54     , m_pageLogicalSizeChanged(false)
55 {
56     setFlowThreadState(InsideOutOfFlowThread);
57 }
58
59 PassRefPtr<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* parentStyle)
60 {
61     RefPtr<RenderStyle> newStyle(RenderStyle::create());
62     newStyle->inheritFrom(parentStyle);
63     newStyle->setDisplay(BLOCK);
64     newStyle->setPosition(AbsolutePosition);
65     newStyle->setZIndex(0);
66     newStyle->setLeft(Length(0, Fixed));
67     newStyle->setTop(Length(0, Fixed));
68     newStyle->setWidth(Length(100, Percent));
69     newStyle->setHeight(Length(100, Percent));
70     newStyle->font().update(0);
71
72     return newStyle.release();
73 }
74
75 void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion)
76 {
77     ASSERT(renderRegion);
78     m_regionList.add(renderRegion);
79     renderRegion->setIsValid(true);
80 }
81
82 void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
83 {
84     ASSERT(renderRegion);
85     m_regionList.remove(renderRegion);
86 }
87
88 void RenderFlowThread::invalidateRegions()
89 {
90     if (m_regionsInvalidated) {
91         ASSERT(selfNeedsLayout());
92         return;
93     }
94
95     m_regionRangeMap.clear();
96     setNeedsLayout();
97
98     m_regionsInvalidated = true;
99 }
100
101 class CurrentRenderFlowThreadDisabler {
102     WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadDisabler);
103 public:
104     CurrentRenderFlowThreadDisabler(RenderView* view)
105         : m_view(view)
106         , m_renderFlowThread(0)
107     {
108         m_renderFlowThread = m_view->flowThreadController()->currentRenderFlowThread();
109         if (m_renderFlowThread)
110             view->flowThreadController()->setCurrentRenderFlowThread(0);
111     }
112     ~CurrentRenderFlowThreadDisabler()
113     {
114         if (m_renderFlowThread)
115             m_view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread);
116     }
117 private:
118     RenderView* m_view;
119     RenderFlowThread* m_renderFlowThread;
120 };
121
122 void RenderFlowThread::validateRegions()
123 {
124     if (m_regionsInvalidated) {
125         m_regionsInvalidated = false;
126         m_regionsHaveUniformLogicalHeight = true;
127
128         if (hasRegions()) {
129             LayoutUnit previousRegionLogicalWidth = 0;
130             LayoutUnit previousRegionLogicalHeight = 0;
131             bool firstRegionVisited = false;
132
133             for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
134                 RenderRegion* region = *iter;
135                 LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
136                 LayoutUnit regionLogicalHeight = region->pageLogicalHeight();
137
138                 if (!firstRegionVisited) {
139                     firstRegionVisited = true;
140                 } else {
141                     if (m_regionsHaveUniformLogicalHeight && previousRegionLogicalHeight != regionLogicalHeight)
142                         m_regionsHaveUniformLogicalHeight = false;
143                 }
144
145                 previousRegionLogicalWidth = regionLogicalWidth;
146             }
147         }
148     }
149
150     updateLogicalWidth(); // Called to get the maximum logical width for the region.
151     updateRegionsFlowThreadPortionRect();
152 }
153
154 void RenderFlowThread::layout()
155 {
156     LayoutRectRecorder recorder(*this);
157     m_pageLogicalSizeChanged = m_regionsInvalidated && everHadLayout();
158
159     validateRegions();
160
161     CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this);
162     RenderBlockFlow::layout();
163
164     m_pageLogicalSizeChanged = false;
165
166     if (lastRegion())
167         lastRegion()->expandToEncompassFlowThreadContentsIfNeeded();
168 }
169
170 void RenderFlowThread::updateLogicalWidth()
171 {
172     setLogicalWidth(initialLogicalWidth());
173 }
174
175 void RenderFlowThread::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
176 {
177     computedValues.m_position = logicalTop;
178     computedValues.m_extent = 0;
179
180     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
181         RenderRegion* region = *iter;
182         computedValues.m_extent += region->logicalHeightOfAllFlowThreadContent();
183     }
184 }
185
186 LayoutRect RenderFlowThread::computeRegionClippingRect(const LayoutPoint& offset, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect) const
187 {
188     LayoutRect regionClippingRect(offset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size());
189     if (style()->isFlippedBlocksWritingMode())
190         regionClippingRect.move(flowThreadPortionRect.size() - flowThreadPortionOverflowRect.size());
191     return regionClippingRect;
192 }
193
194 bool RenderFlowThread::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
195 {
196     if (hitTestAction == HitTestBlockBackground)
197         return false;
198     return RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction);
199 }
200
201 bool RenderFlowThread::shouldRepaint(const LayoutRect& r) const
202 {
203     if (view()->document().printing() || r.isEmpty())
204         return false;
205
206     return true;
207 }
208
209 void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect) const
210 {
211     if (!shouldRepaint(repaintRect) || !hasValidRegionInfo())
212         return;
213
214     LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the regions are somewhere else.
215
216     // We can't use currentFlowThread as it is possible to have interleaved flow threads and the wrong one could be used.
217     // Let each region figure out the proper enclosing flow thread.
218     CurrentRenderFlowThreadDisabler disabler(view());
219
220     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
221         RenderRegion* region = *iter;
222
223         region->repaintFlowThreadContent(repaintRect);
224     }
225 }
226
227 RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool extendLastRegion, RegionAutoGenerationPolicy autoGenerationPolicy)
228 {
229     ASSERT(!m_regionsInvalidated);
230
231     if (autoGenerationPolicy == AllowRegionAutoGeneration)
232         autoGenerateRegionsToBlockOffset(offset);
233
234     if (offset <= 0)
235         return m_regionList.isEmpty() ? 0 : m_regionList.first();
236
237     RegionSearchAdapter adapter(offset);
238     m_regionIntervalTree.allOverlapsWithAdapter<RegionSearchAdapter>(adapter);
239
240     // If no region was found, the offset is in the flow thread overflow.
241     // The last region will contain the offset if extendLastRegion is set or if the last region is a set.
242     if (!adapter.result() && !m_regionList.isEmpty())
243         return m_regionList.last();
244
245     return adapter.result();
246 }
247
248 RenderRegion* RenderFlowThread::regionFromAbsolutePointAndBox(IntPoint absolutePoint, const RenderBox* flowedBox)
249 {
250     if (!flowedBox)
251         return 0;
252
253     RenderRegion* startRegion = 0;
254     RenderRegion* endRegion = 0;
255     getRegionRangeForBox(flowedBox, startRegion, endRegion);
256
257     if (!startRegion)
258         return 0;
259
260     for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) {
261         RenderRegion* region = *iter;
262         IntRect regionAbsoluteRect(roundedIntPoint(region->localToAbsolute()), roundedIntSize(region->frameRect().size()));
263         if (regionAbsoluteRect.contains(absolutePoint))
264             return region;
265
266         if (region == endRegion)
267             break;
268     }
269
270     return 0;
271 }
272
273 LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint)
274 {
275     LayoutPoint referencePoint = startPoint;
276
277     // FIXME: This needs to be adapted for different writing modes inside the flow thread.
278     RenderRegion* startRegion = regionAtBlockOffset(referencePoint.y());
279     if (startRegion) {
280         // Take into account the offset coordinates of the region.
281         RenderObject* currObject = startRegion;
282         RenderObject* currOffsetParentRenderer;
283         Element* currOffsetParentElement;
284         while ((currOffsetParentElement = currObject->offsetParent()) && (currOffsetParentRenderer = currOffsetParentElement->renderer())) {
285             if (currObject->isBoxModelObject())
286                 referencePoint.move(toRenderBoxModelObject(currObject)->offsetLeft(), toRenderBoxModelObject(currObject)->offsetTop());
287
288             // Since we're looking for the offset relative to the body, we must also
289             // take into consideration the borders of the region's offsetParent.
290             if (currOffsetParentRenderer->isBox() && !currOffsetParentRenderer->isBody())
291                 referencePoint.move(toRenderBox(currOffsetParentRenderer)->borderLeft(), toRenderBox(currOffsetParentRenderer)->borderTop());
292
293             currObject = currOffsetParentRenderer;
294         }
295
296         // We need to check if any of this box's containing blocks start in a different region
297         // and if so, drop the object's top position (which was computed relative to its containing block
298         // and is no longer valid) and recompute it using the region in which it flows as reference.
299         bool wasComputedRelativeToOtherRegion = false;
300         const RenderBlock* objContainingBlock = boxModelObject.containingBlock();
301         while (objContainingBlock) {
302             // Check if this object is in a different region.
303             RenderRegion* parentStartRegion = 0;
304             RenderRegion* parentEndRegion = 0;
305             getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEndRegion);
306             if (parentStartRegion && parentStartRegion != startRegion) {
307                 wasComputedRelativeToOtherRegion = true;
308                 break;
309             }
310             objContainingBlock = objContainingBlock->containingBlock();
311         }
312
313         if (wasComputedRelativeToOtherRegion) {
314             // Get the logical top coordinate of the current object.
315             LayoutUnit top = 0;
316             if (boxModelObject.isRenderBlock()) {
317                 top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirstPage();
318             } else {
319                 if (boxModelObject.containingBlock())
320                     top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage();
321
322                 if (boxModelObject.isBox())
323                     top += toRenderBox(&boxModelObject)->topLeftLocation().y();
324                 else if (boxModelObject.isRenderInline())
325                     top -= toRenderInline(&boxModelObject)->borderTop();
326             }
327
328             // Get the logical top of the region this object starts in
329             // and compute the object's top, relative to the region's top.
330             LayoutUnit regionLogicalTop = startRegion->pageLogicalTopForOffset(top);
331             LayoutUnit topRelativeToRegion = top - regionLogicalTop;
332             referencePoint.setY(startRegion->offsetTop() + topRelativeToRegion);
333
334             // Since the top has been overriden, check if the
335             // relative/sticky positioning must be reconsidered.
336             if (boxModelObject.isRelPositioned())
337                 referencePoint.move(0, boxModelObject.relativePositionOffset().height());
338             else if (boxModelObject.isStickyPositioned())
339                 referencePoint.move(0, boxModelObject.stickyPositionOffset().height());
340         }
341
342         // Since we're looking for the offset relative to the body, we must also
343         // take into consideration the borders of the region.
344         referencePoint.move(startRegion->borderLeft(), startRegion->borderTop());
345     }
346
347     return referencePoint;
348 }
349
350 LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset)
351 {
352     RenderRegion* region = regionAtBlockOffset(offset);
353     return region ? region->pageLogicalTopForOffset(offset) : LayoutUnit();
354 }
355
356 LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset)
357 {
358     RenderRegion* region = regionAtBlockOffset(offset, true);
359     return region ? region->pageLogicalWidth() : contentLogicalWidth();
360 }
361
362 LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset)
363 {
364     RenderRegion* region = regionAtBlockOffset(offset);
365     if (!region)
366         return 0;
367
368     return region->pageLogicalHeight();
369 }
370
371 LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule)
372 {
373     RenderRegion* region = regionAtBlockOffset(offset);
374     if (!region)
375         return 0;
376
377     LayoutUnit pageLogicalTop = region->pageLogicalTopForOffset(offset);
378     LayoutUnit pageLogicalHeight = region->pageLogicalHeight();
379     LayoutUnit pageLogicalBottom = pageLogicalTop + pageLogicalHeight;
380     LayoutUnit remainingHeight = pageLogicalBottom - offset;
381     if (pageBoundaryRule == IncludePageBoundary) {
382         // If IncludePageBoundary is set, the line exactly on the top edge of a
383         // region will act as being part of the previous region.
384         remainingHeight = intMod(remainingHeight, pageLogicalHeight);
385     }
386     return remainingHeight;
387 }
388
389 RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformState) const
390 {
391     if (!hasValidRegionInfo())
392         return 0;
393
394     LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox();
395     flipForWritingMode(boxRect);
396
397     // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions,
398     // for now we just take the center of the mapped enclosing box and map it to a region.
399     // Note: Using the center in order to avoid rounding errors.
400
401     LayoutPoint center = boxRect.center();
402     RenderRegion* renderRegion = const_cast<RenderFlowThread*>(this)->regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true, DisallowRegionAutoGeneration);
403     if (!renderRegion)
404         return 0;
405
406     LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect());
407     flipForWritingMode(flippedRegionRect);
408
409     transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location());
410
411     return renderRegion;
412 }
413
414 RenderRegion* RenderFlowThread::firstRegion() const
415 {
416     if (!hasValidRegionInfo())
417         return 0;
418     return m_regionList.first();
419 }
420
421 RenderRegion* RenderFlowThread::lastRegion() const
422 {
423     if (!hasValidRegionInfo())
424         return 0;
425     return m_regionList.last();
426 }
427
428 void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit offsetFromLogicalTopOfFirstPage)
429 {
430     if (!hasRegions())
431         return;
432
433     // FIXME: Not right for differing writing-modes.
434     RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage, true);
435     RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight(), true);
436     RenderRegionRangeMap::iterator it = m_regionRangeMap.find(box);
437     if (it == m_regionRangeMap.end()) {
438         m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion));
439         return;
440     }
441
442     // If nothing changed, just bail.
443     RenderRegionRange& range = it->value;
444     if (range.startRegion() == startRegion && range.endRegion() == endRegion)
445         return;
446
447     range.setRange(startRegion, endRegion);
448 }
449
450 void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*& startRegion, RenderRegion*& endRegion) const
451 {
452     startRegion = 0;
453     endRegion = 0;
454     RenderRegionRangeMap::const_iterator it = m_regionRangeMap.find(box);
455     if (it == m_regionRangeMap.end())
456         return;
457
458     const RenderRegionRange& range = it->value;
459     startRegion = range.startRegion();
460     endRegion = range.endRegion();
461     ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion));
462 }
463
464 void RenderFlowThread::applyBreakAfterContent(LayoutUnit clientHeight)
465 {
466     // Simulate a region break at height. If it points inside an auto logical height region,
467     // then it may determine the region computed autoheight.
468     addForcedRegionBreak(clientHeight, this, false);
469 }
470
471 bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const
472 {
473     ASSERT(targetRegion);
474
475     for (RenderRegionList::const_iterator it = m_regionList.find(const_cast<RenderRegion*>(startRegion)); it != m_regionList.end(); ++it) {
476         const RenderRegion* currRegion = *it;
477         if (targetRegion == currRegion)
478             return true;
479         if (currRegion == endRegion)
480             break;
481     }
482
483     return false;
484 }
485
486 void RenderFlowThread::updateRegionsFlowThreadPortionRect()
487 {
488     LayoutUnit logicalHeight = 0;
489     // FIXME: Optimize not to clear the interval all the time. This implies manually managing the tree nodes lifecycle.
490     m_regionIntervalTree.clear();
491     m_regionIntervalTree.initIfNeeded();
492     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
493         RenderRegion* region = *iter;
494
495         LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
496         LayoutUnit regionLogicalHeight = std::min<LayoutUnit>(RenderFlowThread::maxLogicalHeight() - logicalHeight, region->logicalHeightOfAllFlowThreadContent());
497
498         LayoutRect regionRect(style()->direction() == LTR ? LayoutUnit() : logicalWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogicalHeight);
499
500         region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect());
501
502         m_regionIntervalTree.add(RegionIntervalTree::createInterval(logicalHeight, logicalHeight + regionLogicalHeight, region));
503
504         logicalHeight += regionLogicalHeight;
505     }
506 }
507
508 void RenderFlowThread::collectLayerFragments(LayerFragments& layerFragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
509 {
510     ASSERT(!m_regionsInvalidated);
511
512     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
513         RenderRegion* region = *iter;
514         region->collectLayerFragments(layerFragments, layerBoundingBox, dirtyRect);
515     }
516 }
517
518 LayoutRect RenderFlowThread::fragmentsBoundingBox(const LayoutRect& layerBoundingBox)
519 {
520     ASSERT(!m_regionsInvalidated);
521
522     LayoutRect result;
523     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
524         RenderRegion* region = *iter;
525         LayerFragments fragments;
526         region->collectLayerFragments(fragments, layerBoundingBox, PaintInfo::infiniteRect());
527         for (size_t i = 0; i < fragments.size(); ++i) {
528             const LayerFragment& fragment = fragments.at(i);
529             LayoutRect fragmentRect(layerBoundingBox);
530             fragmentRect.intersect(fragment.paginationClip);
531             fragmentRect.moveBy(fragment.paginationOffset);
532             result.unite(fragmentRect);
533         }
534     }
535
536     return result;
537 }
538
539 bool RenderFlowThread::cachedOffsetFromLogicalTopOfFirstRegion(const RenderBox* box, LayoutUnit& result) const
540 {
541     RenderBoxToOffsetMap::const_iterator offsetIterator = m_boxesToOffsetMap.find(box);
542     if (offsetIterator == m_boxesToOffsetMap.end())
543         return false;
544
545     result = offsetIterator->value;
546     return true;
547 }
548
549 void RenderFlowThread::setOffsetFromLogicalTopOfFirstRegion(const RenderBox* box, LayoutUnit offset)
550 {
551     m_boxesToOffsetMap.set(box, offset);
552 }
553
554 void RenderFlowThread::clearOffsetFromLogicalTopOfFirstRegion(const RenderBox* box)
555 {
556     ASSERT(m_boxesToOffsetMap.contains(box));
557     m_boxesToOffsetMap.remove(box);
558 }
559
560 const RenderBox* RenderFlowThread::currentStatePusherRenderBox() const
561 {
562     const RenderObject* currentObject = m_statePusherObjectsStack.isEmpty() ? 0 : m_statePusherObjectsStack.last();
563     if (currentObject && currentObject->isBox())
564         return toRenderBox(currentObject);
565
566     return 0;
567 }
568
569 void RenderFlowThread::pushFlowThreadLayoutState(const RenderObject* object)
570 {
571     if (const RenderBox* currentBoxDescendant = currentStatePusherRenderBox()) {
572         LayoutState* layoutState = currentBoxDescendant->view()->layoutState();
573         if (layoutState && layoutState->isPaginated()) {
574             ASSERT(layoutState->renderer() == currentBoxDescendant);
575             LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
576             setOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant, currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width());
577         }
578     }
579
580     m_statePusherObjectsStack.add(object);
581 }
582
583 void RenderFlowThread::popFlowThreadLayoutState()
584 {
585     m_statePusherObjectsStack.removeLast();
586
587     if (const RenderBox* currentBoxDescendant = currentStatePusherRenderBox()) {
588         LayoutState* layoutState = currentBoxDescendant->view()->layoutState();
589         if (layoutState && layoutState->isPaginated())
590             clearOffsetFromLogicalTopOfFirstRegion(currentBoxDescendant);
591     }
592 }
593
594 LayoutUnit RenderFlowThread::offsetFromLogicalTopOfFirstRegion(const RenderBlock* currentBlock) const
595 {
596     // First check if we cached the offset for the block if it's an ancestor containing block of the box
597     // being currently laid out.
598     LayoutUnit offset;
599     if (cachedOffsetFromLogicalTopOfFirstRegion(currentBlock, offset))
600         return offset;
601
602     // If it's the current box being laid out, use the layout state.
603     const RenderBox* currentBoxDescendant = currentStatePusherRenderBox();
604     if (currentBlock == currentBoxDescendant) {
605         LayoutState* layoutState = view()->layoutState();
606         ASSERT(layoutState->renderer() == currentBlock);
607         ASSERT(layoutState && layoutState->isPaginated());
608         LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
609         return currentBoxDescendant->isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
610     }
611
612     // As a last resort, take the slow path.
613     LayoutRect blockRect(0, 0, currentBlock->width(), currentBlock->height());
614     while (currentBlock && !currentBlock->isRenderFlowThread()) {
615         RenderBlock* containerBlock = currentBlock->containingBlock();
616         ASSERT(containerBlock);
617         if (!containerBlock)
618             return 0;
619         LayoutPoint currentBlockLocation = currentBlock->location();
620
621         if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
622             // We have to put the block rect in container coordinates
623             // and we have to take into account both the container and current block flipping modes
624             if (containerBlock->style()->isFlippedBlocksWritingMode()) {
625                 if (containerBlock->isHorizontalWritingMode())
626                     blockRect.setY(currentBlock->height() - blockRect.maxY());
627                 else
628                     blockRect.setX(currentBlock->width() - blockRect.maxX());
629             }
630             currentBlock->flipForWritingMode(blockRect);
631         }
632         blockRect.moveBy(currentBlockLocation);
633         currentBlock = containerBlock;
634     }
635
636     return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
637 }
638
639 void RenderFlowThread::RegionSearchAdapter::collectIfNeeded(const RegionInterval& interval)
640 {
641     if (m_result)
642         return;
643     if (interval.low() <= m_offset && interval.high() > m_offset)
644         m_result = interval.data();
645 }
646
647 void RenderFlowThread::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
648 {
649     if (this == repaintContainer)
650         return;
651
652     if (RenderRegion* region = mapFromFlowToRegion(transformState)) {
653         // FIXME: The cast below is probably not the best solution, we may need to find a better way.
654         static_cast<const RenderObject*>(region)->mapLocalToContainer(region->containerForRepaint(), transformState, mode, wasFixed);
655     }
656 }
657
658 CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowThread* renderFlowThread)
659     : m_renderFlowThread(renderFlowThread)
660     , m_previousRenderFlowThread(0)
661 {
662     if (!m_renderFlowThread)
663         return;
664     RenderView* view = m_renderFlowThread->view();
665     m_previousRenderFlowThread = view->flowThreadController()->currentRenderFlowThread();
666     view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread);
667 }
668
669 CurrentRenderFlowThreadMaintainer::~CurrentRenderFlowThreadMaintainer()
670 {
671     if (!m_renderFlowThread)
672         return;
673     RenderView* view = m_renderFlowThread->view();
674     ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFlowThread);
675     view->flowThreadController()->setCurrentRenderFlowThread(m_previousRenderFlowThread);
676 }
677
678
679 } // namespace WebCore