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