0741ea8c8af482e25a9c5cc42be4f89f3f453164
[WebKit-https.git] / Source / WebCore / rendering / RenderFlowThread.cpp
1 /*
2  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "config.h"
31
32 #include "RenderFlowThread.h"
33
34 #include "FlowThreadController.h"
35 #include "HitTestRequest.h"
36 #include "HitTestResult.h"
37 #include "Node.h"
38 #include "PaintInfo.h"
39 #include "RenderBoxRegionInfo.h"
40 #include "RenderLayer.h"
41 #include "RenderRegion.h"
42 #include "RenderView.h"
43 #include "TransformState.h"
44 #include "WebKitNamedFlow.h"
45
46 namespace WebCore {
47
48 RenderFlowThread::RenderFlowThread(Node* node)
49     : RenderBlock(node)
50     , m_hasValidRegions(false)
51     , m_regionsInvalidated(false)
52     , m_regionsHaveUniformLogicalWidth(true)
53     , m_regionsHaveUniformLogicalHeight(true)
54     , m_overset(true)
55     , m_hasRegionsWithStyling(false)
56     , m_dispatchRegionLayoutUpdateEvent(false)
57     , m_pageLogicalHeightChanged(false)
58 {
59     ASSERT(node->document()->cssRegionsEnabled());
60     setIsAnonymous(false);
61     setInRenderFlowThread();
62 }
63
64 PassRefPtr<RenderStyle> RenderFlowThread::createFlowThreadStyle(RenderStyle* parentStyle)
65 {
66     RefPtr<RenderStyle> newStyle(RenderStyle::create());
67     newStyle->inheritFrom(parentStyle);
68     newStyle->setDisplay(BLOCK);
69     newStyle->setPosition(AbsolutePosition);
70     newStyle->setZIndex(0);
71     newStyle->setLeft(Length(0, Fixed));
72     newStyle->setTop(Length(0, Fixed));
73     newStyle->setWidth(Length(100, Percent));
74     newStyle->setHeight(Length(100, Percent));
75     newStyle->font().update(0);
76     
77     return newStyle.release();
78 }
79
80 void RenderFlowThread::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
81 {
82     RenderBlock::styleDidChange(diff, oldStyle);
83
84     if (oldStyle && oldStyle->writingMode() != style()->writingMode())
85         m_regionsInvalidated = true;
86 }
87
88 void RenderFlowThread::removeFlowChildInfo(RenderObject* child)
89 {
90     if (child->isBox())
91         removeRenderBoxRegionInfo(toRenderBox(child));
92     clearRenderObjectCustomStyle(child);
93 }
94
95 void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion)
96 {
97     ASSERT(renderRegion);
98     m_regionList.add(renderRegion);
99     renderRegion->setIsValid(true);
100     invalidateRegions();
101     checkRegionsWithStyling();
102 }
103
104 void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
105 {
106     ASSERT(renderRegion);
107     m_regionRangeMap.clear();
108     m_regionList.remove(renderRegion);
109     invalidateRegions();
110     checkRegionsWithStyling();
111 }
112
113 class CurrentRenderFlowThreadDisabler {
114     WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadDisabler);
115 public:
116     CurrentRenderFlowThreadDisabler(RenderView* view)
117         : m_view(view)
118         , m_renderFlowThread(0)
119     {
120         m_renderFlowThread = m_view->flowThreadController()->currentRenderFlowThread();
121         if (m_renderFlowThread)
122             view->flowThreadController()->setCurrentRenderFlowThread(0);
123     }
124     ~CurrentRenderFlowThreadDisabler()
125     {
126         if (m_renderFlowThread)
127             m_view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread);
128     }
129 private:
130     RenderView* m_view;
131     RenderFlowThread* m_renderFlowThread;
132 };
133
134 void RenderFlowThread::layout()
135 {
136     m_pageLogicalHeightChanged = m_regionsInvalidated && everHadLayout();
137     if (m_regionsInvalidated) {
138         m_regionsInvalidated = false;
139         m_hasValidRegions = false;
140         m_regionsHaveUniformLogicalWidth = true;
141         m_regionsHaveUniformLogicalHeight = true;
142         m_regionRangeMap.clear();
143         LayoutUnit previousRegionLogicalWidth = 0;
144         LayoutUnit previousRegionLogicalHeight = 0;
145         if (hasRegions()) {
146             for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
147                 RenderRegion* region = *iter;
148                 if (!region->isValid())
149                     continue;
150                 ASSERT(!region->needsLayout());
151                 
152                 region->deleteAllRenderBoxRegionInfo();
153
154                 LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
155                 LayoutUnit regionLogicalHeight = region->pageLogicalHeight();
156
157                 if (!m_hasValidRegions)
158                     m_hasValidRegions = true;
159                 else {
160                     if (m_regionsHaveUniformLogicalWidth && previousRegionLogicalWidth != regionLogicalWidth)
161                         m_regionsHaveUniformLogicalWidth = false;
162                     if (m_regionsHaveUniformLogicalHeight && previousRegionLogicalHeight != regionLogicalHeight)
163                         m_regionsHaveUniformLogicalHeight = false;
164                 }
165
166                 previousRegionLogicalWidth = regionLogicalWidth;
167             }
168             
169             updateLogicalWidth(); // Called to get the maximum logical width for the region.
170             
171             LayoutUnit logicalHeight = 0;
172             for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
173                 RenderRegion* region = *iter;
174                 if (!region->isValid())
175                     continue;
176                     
177                 LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
178                 LayoutUnit regionLogicalHeight = region->logicalHeightOfAllFlowThreadContent();
179     
180                 LayoutRect regionRect(style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogicalHeight);
181                 region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect());
182                 logicalHeight += regionLogicalHeight;
183             }
184         }
185     }
186
187     CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this);
188     RenderBlock::layout();
189
190     m_pageLogicalHeightChanged = false;
191
192     if (lastRegion())
193         lastRegion()->expandToEncompassFlowThreadContentsIfNeeded();
194
195     if (shouldDispatchRegionLayoutUpdateEvent())
196         dispatchRegionLayoutUpdateEvent();
197 }
198
199 void RenderFlowThread::updateLogicalWidth()
200 {
201     LayoutUnit logicalWidth = 0;
202     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
203         RenderRegion* region = *iter;
204         if (!region->isValid())
205             continue;
206         ASSERT(!region->needsLayout());
207         logicalWidth = max(region->pageLogicalWidth(), logicalWidth);
208     }
209     setLogicalWidth(logicalWidth);
210
211     // If the regions have non-uniform logical widths, then insert inset information for the RenderFlowThread.
212     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
213         RenderRegion* region = *iter;
214         if (!region->isValid())
215             continue;
216         
217         LayoutUnit regionLogicalWidth = region->pageLogicalWidth();
218         if (regionLogicalWidth != logicalWidth) {
219             LayoutUnit logicalLeft = style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth - regionLogicalWidth;
220             region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth, false);
221         }
222     }
223 }
224
225 void RenderFlowThread::updateLogicalHeight()
226 {
227     LayoutUnit logicalHeight = 0;
228
229     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
230         RenderRegion* region = *iter;
231         if (!region->isValid())
232             continue;
233         ASSERT(!region->needsLayout());
234         logicalHeight += region->logicalHeightOfAllFlowThreadContent();
235     }
236
237     setLogicalHeight(logicalHeight);
238 }
239
240 void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const
241 {
242     GraphicsContext* context = paintInfo.context;
243     if (!context)
244         return;
245
246     // Adjust the clipping rect for the region.
247     // paintOffset contains the offset where the painting should occur
248     // adjusted with the region padding and border.
249     LayoutRect regionClippingRect(paintOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size());
250
251     PaintInfo info(paintInfo);
252     info.rect.intersect(pixelSnappedIntRect(regionClippingRect));
253
254     if (!info.rect.isEmpty()) {
255         context->save();
256
257         context->clip(regionClippingRect);
258
259         // RenderFlowThread should start painting its content in a position that is offset
260         // from the region rect's current position. The amount of offset is equal to the location of
261         // the flow thread portion in the flow thread's local coordinates.
262         IntPoint renderFlowThreadOffset;
263         if (style()->isFlippedBlocksWritingMode()) {
264             LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
265             flipForWritingMode(flippedFlowThreadPortionRect);
266             renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedFlowThreadPortionRect.location());
267         } else
268             renderFlowThreadOffset = roundedIntPoint(paintOffset - flowThreadPortionRect.location());
269
270         context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y());
271         info.rect.moveBy(-renderFlowThreadOffset);
272         
273         layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects);
274
275         context->restore();
276     }
277 }
278
279 bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const
280 {
281     LayoutRect regionClippingRect(accumulatedOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size());
282     if (!regionClippingRect.contains(locationInContainer.point()))
283         return false;
284
285     LayoutSize renderFlowThreadOffset;
286     if (style()->isFlippedBlocksWritingMode()) {
287         LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect);
288         flipForWritingMode(flippedFlowThreadPortionRect);
289         renderFlowThreadOffset = accumulatedOffset - flippedFlowThreadPortionRect.location();
290     } else
291         renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.location();
292
293     // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView.
294     HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping);
295
296     // Make a new temporary HitTestLocation in the new region.
297     HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOffset, region);
298
299     bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestLocation, result);
300
301     // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate
302     // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to
303     // patching positionForPoint.
304     return isPointInsideFlowThread;
305 }
306
307 bool RenderFlowThread::shouldRepaint(const LayoutRect& r) const
308 {
309     if (view()->printing() || r.isEmpty())
310         return false;
311
312     return true;
313 }
314
315 void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect, bool immediate)
316 {
317     if (!shouldRepaint(repaintRect) || !hasValidRegionInfo())
318         return;
319
320     LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the regions are somewhere else.
321
322     // We can't use currentFlowThread as it is possible to have interleaved flow threads and the wrong one could be used.
323     // Let each region figure out the proper enclosing flow thread.
324     CurrentRenderFlowThreadDisabler disabler(view());
325     
326     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
327         RenderRegion* region = *iter;
328         if (!region->isValid())
329             continue;
330
331         region->repaintFlowThreadContent(repaintRect, immediate);
332     }
333 }
334
335 RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool extendLastRegion) const
336 {
337     ASSERT(!m_regionsInvalidated);
338
339     // If no region matches the position and extendLastRegion is true, it will return
340     // the last valid region. It is similar to auto extending the size of the last region. 
341     RenderRegion* lastValidRegion = 0;
342     
343     // FIXME: The regions are always in order, optimize this search.
344     bool useHorizontalWritingMode = isHorizontalWritingMode();
345     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
346         RenderRegion* region = *iter;
347         if (!region->isValid())
348             continue;
349
350         if (offset <= 0)
351             return region;
352
353         LayoutRect regionRect = region->flowThreadPortionRect();
354         if ((useHorizontalWritingMode && offset < regionRect.maxY()) || (!useHorizontalWritingMode && offset < regionRect.maxX()))
355             return region;
356
357         if (extendLastRegion || region->isRenderRegionSet())
358             lastValidRegion = region;
359     }
360
361     return lastValidRegion;
362 }
363
364 LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset) const
365 {
366     RenderRegion* region = regionAtBlockOffset(offset);
367     return region ? region->pageLogicalTopForOffset(offset) : ZERO_LAYOUT_UNIT;
368 }
369
370 LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset) const
371 {
372     RenderRegion* region = regionAtBlockOffset(offset, true);
373     return region ? region->pageLogicalWidth() : contentLogicalWidth();
374 }
375
376 LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset) const
377 {
378     RenderRegion* region = regionAtBlockOffset(offset);
379     return region ? region->pageLogicalHeight() : ZERO_LAYOUT_UNIT;
380 }
381
382 LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
383 {
384     RenderRegion* region = regionAtBlockOffset(offset);
385     if (!region)
386         return ZERO_LAYOUT_UNIT;
387     
388     LayoutUnit pageLogicalTop = region->pageLogicalTopForOffset(offset);
389     LayoutUnit pageLogicalHeight = region->pageLogicalHeight();
390     LayoutUnit pageLogicalBottom = pageLogicalTop + pageLogicalHeight;
391     LayoutUnit remainingHeight = pageLogicalBottom - offset;
392     if (pageBoundaryRule == IncludePageBoundary) {
393         // If IncludePageBoundary is set, the line exactly on the top edge of a
394         // region will act as being part of the previous region.
395         remainingHeight = intMod(remainingHeight, pageLogicalHeight);
396     }
397     return remainingHeight;
398 }
399
400 RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformState) const
401 {
402     if (!hasValidRegionInfo())
403         return 0;
404
405     LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox();
406     flipForWritingMode(boxRect);
407
408     // FIXME: We need to refactor RenderObject::absoluteQuads to be able to split the quads across regions,
409     // for now we just take the center of the mapped enclosing box and map it to a region.
410     // Note: Using the center in order to avoid rounding errors.
411
412     LayoutPoint center = boxRect.center();
413     RenderRegion* renderRegion = regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true);
414     if (!renderRegion)
415         return 0;
416
417     LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect());
418     flipForWritingMode(flippedRegionRect);
419
420     transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location());
421
422     return renderRegion;
423 }
424
425 void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box)
426 {
427     if (!hasRegions())
428         return;
429
430     RenderRegion* startRegion;
431     RenderRegion* endRegion;
432     getRegionRangeForBox(box, startRegion, endRegion);
433
434     for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) {
435         RenderRegion* region = *iter;
436         if (!region->isValid())
437             continue;
438         region->removeRenderBoxRegionInfo(box);
439         if (region == endRegion)
440             break;
441     }
442
443 #ifndef NDEBUG
444     // We have to make sure we did not leave any RenderBoxRegionInfo attached.
445     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
446         RenderRegion* region = *iter;
447         if (!region->isValid())
448             continue;
449         ASSERT(!region->renderBoxRegionInfo(box));
450     }
451 #endif
452
453     m_regionRangeMap.remove(box);
454 }
455
456 bool RenderFlowThread::logicalWidthChangedInRegions(const RenderBlock* block, LayoutUnit offsetFromLogicalTopOfFirstPage)
457 {
458     if (!hasRegions() || block == this) // Not necessary, since if any region changes, we do a full pagination relayout anyway.
459         return false;
460
461     RenderRegion* startRegion;
462     RenderRegion* endRegion;
463     getRegionRangeForBox(block, startRegion, endRegion);
464
465     for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) {
466         RenderRegion* region = *iter;
467         
468         if (!region->isValid())
469             continue;
470
471         ASSERT(!region->needsLayout());
472
473         OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block);
474         if (!oldInfo)
475             continue;
476
477         LayoutUnit oldLogicalWidth = oldInfo->logicalWidth();
478         RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region, offsetFromLogicalTopOfFirstPage);
479         if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth)
480             return true;
481
482         if (region == endRegion)
483             break;
484     }
485
486     return false;
487 }
488
489 LayoutUnit RenderFlowThread::contentLogicalWidthOfFirstRegion() const
490 {
491     if (!hasValidRegionInfo())
492         return 0;
493     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
494         RenderRegion* region = *iter;
495         if (!region->isValid())
496             continue;
497         return isHorizontalWritingMode() ? region->contentWidth() : region->contentHeight();
498     }
499     ASSERT_NOT_REACHED();
500     return 0;
501 }
502
503 LayoutUnit RenderFlowThread::contentLogicalHeightOfFirstRegion() const
504 {
505     if (!hasValidRegionInfo())
506         return 0;
507     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
508         RenderRegion* region = *iter;
509         if (!region->isValid())
510             continue;
511         return isHorizontalWritingMode() ? region->contentHeight() : region->contentWidth();
512     }
513     ASSERT_NOT_REACHED();
514     return 0;
515 }
516  
517 LayoutUnit RenderFlowThread::contentLogicalLeftOfFirstRegion() const
518 {
519     if (!hasValidRegionInfo())
520         return 0;
521     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
522         RenderRegion* region = *iter;
523         if (!region->isValid())
524             continue;
525         return isHorizontalWritingMode() ? region->flowThreadPortionRect().x() : region->flowThreadPortionRect().y();
526     }
527     ASSERT_NOT_REACHED();
528     return 0;
529 }
530
531 RenderRegion* RenderFlowThread::firstRegion() const
532 {
533     if (!hasValidRegionInfo())
534         return 0;
535     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
536         RenderRegion* region = *iter;
537         if (!region->isValid())
538             continue;
539         return region;
540     }
541     return 0;
542 }
543
544 RenderRegion* RenderFlowThread::lastRegion() const
545 {
546     if (!hasValidRegionInfo())
547         return 0;
548     for (RenderRegionList::const_reverse_iterator iter = m_regionList.rbegin(); iter != m_regionList.rend(); ++iter) {
549         RenderRegion* region = *iter;
550         if (!region->isValid())
551             continue;
552         return region;
553     }
554     return 0;
555 }
556
557 void RenderFlowThread::clearRenderObjectCustomStyle(const RenderObject* object,
558     const RenderRegion* oldStartRegion, const RenderRegion* oldEndRegion,
559     const RenderRegion* newStartRegion, const RenderRegion* newEndRegion)
560 {
561     // Clear the styles for the object in the regions.
562     // The styles are not cleared for the regions that are contained in both ranges.
563     bool insideOldRegionRange = false;
564     bool insideNewRegionRange = false;
565     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
566         RenderRegion* region = *iter;
567
568         if (oldStartRegion == region)
569             insideOldRegionRange = true;
570         if (newStartRegion == region)
571             insideNewRegionRange = true;
572
573         if (!(insideOldRegionRange && insideNewRegionRange))
574             region->clearObjectStyleInRegion(object);
575
576         if (oldEndRegion == region)
577             insideOldRegionRange = false;
578         if (newEndRegion == region)
579             insideNewRegionRange = false;
580     }
581 }
582
583 void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit offsetFromLogicalTopOfFirstPage)
584 {
585     if (!hasRegions())
586         return;
587
588     // FIXME: Not right for differing writing-modes.
589     RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage, true);
590     RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight(), true);
591     RenderRegionRangeMap::iterator it = m_regionRangeMap.find(box);
592     if (it == m_regionRangeMap.end()) {
593         m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion));
594         clearRenderObjectCustomStyle(box);
595         return;
596     }
597
598     // If nothing changed, just bail.
599     RenderRegionRange& range = it->second;
600     if (range.startRegion() == startRegion && range.endRegion() == endRegion)
601         return;
602
603     // Delete any info that we find before our new startRegion and after our new endRegion.
604     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
605         RenderRegion* region = *iter;
606         if (region == startRegion) {
607             iter = m_regionList.find(endRegion);
608             continue;
609         }
610
611         region->removeRenderBoxRegionInfo(box);
612
613         if (region == range.endRegion())
614             break;
615     }
616
617     clearRenderObjectCustomStyle(box, range.startRegion(), range.endRegion(), startRegion, endRegion);
618     range.setRange(startRegion, endRegion);
619 }
620
621 void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*& startRegion, RenderRegion*& endRegion) const
622 {
623     startRegion = 0;
624     endRegion = 0;
625     RenderRegionRangeMap::const_iterator it = m_regionRangeMap.find(box);
626     if (it == m_regionRangeMap.end())
627         return;
628
629     const RenderRegionRange& range = it->second;
630     startRegion = range.startRegion();
631     endRegion = range.endRegion();
632     ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion));
633 }
634
635 void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge)
636 {
637     LayoutUnit height = oldClientAfterEdge;
638     // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread)
639     // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow
640     // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height).
641     // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region)
642     if (hasRenderOverflow() && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY()) 
643                                 || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX())))
644         height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX();
645
646     RenderRegion* lastReg = lastRegion();
647     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
648         RenderRegion* region = *iter;
649         if (!region->isValid()) {
650             region->setRegionState(RenderRegion::RegionUndefined);
651             continue;
652         }
653         LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x());
654         LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX());
655         RenderRegion::RegionState previousState = region->regionState();
656         RenderRegion::RegionState state = RenderRegion::RegionFit;
657         if (flowMin <= 0)
658             state = RenderRegion::RegionEmpty;
659         if (flowMax > 0 && region == lastReg)
660             state = RenderRegion::RegionOverset;
661         region->setRegionState(state);
662         // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event
663         // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually
664         // changed, so it just assumes that the NamedFlow should dispatch the event
665         if (previousState != state
666             || state == RenderRegion::RegionFit
667             || state == RenderRegion::RegionOverset)
668             setDispatchRegionLayoutUpdateEvent(true);
669     }
670
671     // With the regions overflow state computed we can also set the overset flag for the named flow.
672     // If there are no valid regions in the chain, overset is true.
673     m_overset = lastReg ? lastReg->regionState() == RenderRegion::RegionOverset : true;
674 }
675
676 bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const
677 {
678     ASSERT(targetRegion);
679
680     for (RenderRegionList::const_iterator it = m_regionList.find(const_cast<RenderRegion*>(startRegion)); it != m_regionList.end(); ++it) {
681         const RenderRegion* currRegion = *it;
682         if (!currRegion->isValid())
683             continue;
684         if (targetRegion == currRegion)
685             return true;
686         if (currRegion == endRegion)
687             break;
688     }
689
690     return false;
691 }
692
693 // Check if the content is flown into at least a region with region styling rules.
694 void RenderFlowThread::checkRegionsWithStyling()
695 {
696     bool hasRegionsWithStyling = false;
697     for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
698         RenderRegion* region = *iter;
699         if (!region->isValid())
700             continue;
701         if (region->hasCustomRegionStyle()) {
702             hasRegionsWithStyling = true;
703             break;
704         }
705     }
706     m_hasRegionsWithStyling = hasRegionsWithStyling;
707 }
708
709 bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const RenderRegion* region) const
710 {
711     ASSERT(object);
712     ASSERT(region);
713
714     if (!object->inRenderFlowThread())
715         return false;
716     if (object->enclosingRenderFlowThread() != this)
717         return false;
718     if (!m_regionList.contains(const_cast<RenderRegion*>(region)))
719         return false;
720
721     RenderBox* enclosingBox = object->enclosingBox();
722     RenderRegion* enclosingBoxStartRegion = 0;
723     RenderRegion* enclosingBoxEndRegion = 0;
724     getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndRegion);
725     if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion))
726        return false;
727
728     if (object->isBox())
729         return true;
730
731     LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true);
732     if (!objectABBRect.width())
733         objectABBRect.setWidth(1);
734     if (!objectABBRect.height())
735         objectABBRect.setHeight(1); 
736     if (objectABBRect.intersects(region->absoluteBoundingBoxRect(true)))
737         return true;
738
739     if (region == lastRegion()) {
740         // If the object does not intersect any of the enclosing box regions
741         // then the object is in last region.
742         for (RenderRegionList::const_iterator it = m_regionList.find(enclosingBoxStartRegion); it != m_regionList.end(); ++it) {
743             const RenderRegion* currRegion = *it;
744             if (!region->isValid())
745                 continue;
746             if (currRegion == region)
747                 break;
748             if (objectABBRect.intersects(currRegion->absoluteBoundingBoxRect(true)))
749                 return false;
750         }
751         return true;
752     }
753
754     return false;
755 }
756
757 #ifndef NDEBUG
758 unsigned RenderFlowThread::autoLogicalHeightRegionsCount() const
759 {
760     unsigned autoLogicalHeightRegions = 0;
761     for (RenderRegionList::const_iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
762         const RenderRegion* region = *iter;
763         if (!region->isValid()) {
764             ASSERT(!region->hasAutoLogicalHeight());
765             continue;
766         }
767
768         if (region->hasAutoLogicalHeight())
769             autoLogicalHeightRegions++;
770     }
771
772     return autoLogicalHeightRegions;
773 }
774 #endif
775
776 CurrentRenderFlowThreadMaintainer::CurrentRenderFlowThreadMaintainer(RenderFlowThread* renderFlowThread)
777         : m_renderFlowThread(renderFlowThread)
778 {
779     if (!m_renderFlowThread)
780         return;
781     RenderView* view = m_renderFlowThread->view();
782     ASSERT(!view->flowThreadController()->currentRenderFlowThread());
783     view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread);
784 }
785
786 CurrentRenderFlowThreadMaintainer::~CurrentRenderFlowThreadMaintainer()
787 {
788     if (!m_renderFlowThread)
789         return;
790     RenderView* view = m_renderFlowThread->view();
791     ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFlowThread);
792     view->flowThreadController()->setCurrentRenderFlowThread(0);
793 }
794
795
796 } // namespace WebCore