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