diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-07 11:21:11 +0200 |
commit | 2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch) | |
tree | 988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/rendering/RenderFlowThread.cpp | |
parent | dd91e772430dc294e3bf478c119ef8d43c0a3358 (diff) | |
download | qtwebkit-2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47.tar.gz |
Imported WebKit commit 7e538425aa020340619e927792f3d895061fb54b (http://svn.webkit.org/repository/webkit/trunk@116286)
Diffstat (limited to 'Source/WebCore/rendering/RenderFlowThread.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderFlowThread.cpp | 272 |
1 files changed, 63 insertions, 209 deletions
diff --git a/Source/WebCore/rendering/RenderFlowThread.cpp b/Source/WebCore/rendering/RenderFlowThread.cpp index e241d9670..393964ade 100644 --- a/Source/WebCore/rendering/RenderFlowThread.cpp +++ b/Source/WebCore/rendering/RenderFlowThread.cpp @@ -31,6 +31,7 @@ #include "RenderFlowThread.h" +#include "FlowThreadController.h" #include "HitTestRequest.h" #include "HitTestResult.h" #include "Node.h" @@ -44,14 +45,14 @@ namespace WebCore { -RenderFlowThread::RenderFlowThread(Node* node, const AtomicString& flowThread) +RenderFlowThread::RenderFlowThread(Node* node) : RenderBlock(node) - , m_flowThread(flowThread) , m_hasValidRegions(false) , m_regionsInvalidated(false) , m_regionsHaveUniformLogicalWidth(true) , m_regionsHaveUniformLogicalHeight(true) , m_overflow(false) + , m_regionLayoutUpdateEventTimer(this, &RenderFlowThread::regionLayoutUpdateEventTimerFired) { ASSERT(node->document()->cssRegionsEnabled()); setIsAnonymous(false); @@ -82,63 +83,6 @@ void RenderFlowThread::styleDidChange(StyleDifference diff, const RenderStyle* o m_regionsInvalidated = true; } -RenderObject* RenderFlowThread::nextRendererForNode(Node* node) const -{ - FlowThreadChildList::const_iterator it = m_flowThreadChildList.begin(); - FlowThreadChildList::const_iterator end = m_flowThreadChildList.end(); - - for (; it != end; ++it) { - RenderObject* child = *it; - ASSERT(child->node()); - unsigned short position = node->compareDocumentPosition(child->node()); - if (position & Node::DOCUMENT_POSITION_FOLLOWING) - return child; - } - - return 0; -} - -RenderObject* RenderFlowThread::previousRendererForNode(Node* node) const -{ - if (m_flowThreadChildList.isEmpty()) - return 0; - - FlowThreadChildList::const_iterator begin = m_flowThreadChildList.begin(); - FlowThreadChildList::const_iterator end = m_flowThreadChildList.end(); - FlowThreadChildList::const_iterator it = end; - - do { - --it; - RenderObject* child = *it; - ASSERT(child->node()); - unsigned short position = node->compareDocumentPosition(child->node()); - if (position & Node::DOCUMENT_POSITION_PRECEDING) - return child; - } while (it != begin); - - return 0; -} - -void RenderFlowThread::addFlowChild(RenderObject* newChild, RenderObject* beforeChild) -{ - // The child list is used to sort the flow thread's children render objects - // based on their corresponding nodes DOM order. The list is needed to avoid searching the whole DOM. - - // Do not add anonymous objects. - if (!newChild->node()) - return; - - if (beforeChild) - m_flowThreadChildList.insertBefore(beforeChild, newChild); - else - m_flowThreadChildList.add(newChild); -} - -void RenderFlowThread::removeFlowChild(RenderObject* child) -{ - m_flowThreadChildList.remove(child); -} - void RenderFlowThread::removeFlowChildInfo(RenderObject* child) { if (child->isBox()) { @@ -148,149 +92,22 @@ void RenderFlowThread::removeFlowChildInfo(RenderObject* child) } } -// Compare two regions to determine in which one the content should flow first. -// The function returns true if the first passed region is "less" than the second passed region. -// If the first region appears before second region in DOM, -// the first region is "less" than the second region. -// If the first region is "less" than the second region, the first region receives content before second region. -static bool compareRenderRegions(const RenderRegion* firstRegion, const RenderRegion* secondRegion) -{ - ASSERT(firstRegion); - ASSERT(secondRegion); - - // If the regions have the same region-index, compare their position in dom. - ASSERT(firstRegion->node()); - ASSERT(secondRegion->node()); - - unsigned short position = firstRegion->node()->compareDocumentPosition(secondRegion->node()); - return (position & Node::DOCUMENT_POSITION_FOLLOWING); -} - -bool RenderFlowThread::dependsOn(RenderFlowThread* otherRenderFlowThread) const -{ - if (m_layoutBeforeThreadsSet.contains(otherRenderFlowThread)) - return true; - - // Recursively traverse the m_layoutBeforeThreadsSet. - RenderFlowThreadCountedSet::const_iterator iterator = m_layoutBeforeThreadsSet.begin(); - RenderFlowThreadCountedSet::const_iterator end = m_layoutBeforeThreadsSet.end(); - for (; iterator != end; ++iterator) { - const RenderFlowThread* beforeFlowThread = (*iterator).first; - if (beforeFlowThread->dependsOn(otherRenderFlowThread)) - return true; - } - - return false; -} - void RenderFlowThread::addRegionToThread(RenderRegion* renderRegion) { ASSERT(renderRegion); - if (m_regionList.isEmpty()) - m_regionList.add(renderRegion); - else { - // Find the first region "greater" than renderRegion. - RenderRegionList::iterator it = m_regionList.begin(); - while (it != m_regionList.end() && !compareRenderRegions(renderRegion, *it)) - ++it; - m_regionList.insertBefore(it, renderRegion); - } - - ASSERT(!renderRegion->isValid()); - if (renderRegion->parentFlowThread()) { - if (renderRegion->parentFlowThread()->dependsOn(this)) { - // Register ourself to get a notification when the state changes. - renderRegion->parentFlowThread()->m_observerThreadsSet.add(this); - return; - } - - addDependencyOnFlowThread(renderRegion->parentFlowThread()); - } - + m_regionList.add(renderRegion); renderRegion->setIsValid(true); - invalidateRegions(); } void RenderFlowThread::removeRegionFromThread(RenderRegion* renderRegion) { ASSERT(renderRegion); - m_regionRangeMap.clear(); m_regionList.remove(renderRegion); - - if (renderRegion->parentFlowThread()) { - if (!renderRegion->isValid()) { - renderRegion->parentFlowThread()->m_observerThreadsSet.remove(this); - // No need to invalidate the regions rectangles. The removed region - // was not taken into account. Just return here. - return; - } - removeDependencyOnFlowThread(renderRegion->parentFlowThread()); - } - invalidateRegions(); } -void RenderFlowThread::checkInvalidRegions() -{ - for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { - RenderRegion* region = *iter; - // The only reason a region would be invalid is because it has a parent flow thread. - ASSERT(region->isValid() || region->parentFlowThread()); - if (region->isValid() || region->parentFlowThread()->dependsOn(this)) - continue; - - region->parentFlowThread()->m_observerThreadsSet.remove(this); - addDependencyOnFlowThread(region->parentFlowThread()); - region->setIsValid(true); - invalidateRegions(); - } - - if (m_observerThreadsSet.isEmpty()) - return; - - // Notify all the flow threads that were dependent on this flow. - - // Create a copy of the list first. That's because observers might change the list when calling checkInvalidRegions. - Vector<RenderFlowThread*> observers; - copyToVector(m_observerThreadsSet, observers); - - for (size_t i = 0; i < observers.size(); ++i) { - RenderFlowThread* flowThread = observers.at(i); - flowThread->checkInvalidRegions(); - } -} - -void RenderFlowThread::addDependencyOnFlowThread(RenderFlowThread* otherFlowThread) -{ - std::pair<RenderFlowThreadCountedSet::iterator, bool> result = m_layoutBeforeThreadsSet.add(otherFlowThread); - if (result.second) { - // This is the first time we see this dependency. Make sure we recalculate all the dependencies. - view()->setIsRenderFlowThreadOrderDirty(true); - } -} - -void RenderFlowThread::removeDependencyOnFlowThread(RenderFlowThread* otherFlowThread) -{ - bool removed = m_layoutBeforeThreadsSet.remove(otherFlowThread); - if (removed) { - checkInvalidRegions(); - view()->setIsRenderFlowThreadOrderDirty(true); - } -} - -void RenderFlowThread::pushDependencies(RenderFlowThreadList& list) -{ - for (RenderFlowThreadCountedSet::iterator iter = m_layoutBeforeThreadsSet.begin(); iter != m_layoutBeforeThreadsSet.end(); ++iter) { - RenderFlowThread* flowThread = (*iter).first; - if (list.contains(flowThread)) - continue; - flowThread->pushDependencies(list); - list.add(flowThread); - } -} - class CurrentRenderFlowThreadMaintainer { WTF_MAKE_NONCOPYABLE(CurrentRenderFlowThreadMaintainer); public: @@ -298,14 +115,14 @@ public: : m_renderFlowThread(renderFlowThread) { RenderView* view = m_renderFlowThread->view(); - ASSERT(!view->currentRenderFlowThread()); - view->setCurrentRenderFlowThread(m_renderFlowThread); + ASSERT(!view->flowThreadController()->currentRenderFlowThread()); + view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread); } ~CurrentRenderFlowThreadMaintainer() { RenderView* view = m_renderFlowThread->view(); - ASSERT(view->currentRenderFlowThread() == m_renderFlowThread); - view->setCurrentRenderFlowThread(0); + ASSERT(view->flowThreadController()->currentRenderFlowThread() == m_renderFlowThread); + view->flowThreadController()->setCurrentRenderFlowThread(0); } private: RenderFlowThread* m_renderFlowThread; @@ -318,14 +135,14 @@ public: : m_view(view) , m_renderFlowThread(0) { - m_renderFlowThread = m_view->currentRenderFlowThread(); + m_renderFlowThread = m_view->flowThreadController()->currentRenderFlowThread(); if (m_renderFlowThread) - view->setCurrentRenderFlowThread(0); + view->flowThreadController()->setCurrentRenderFlowThread(0); } ~CurrentRenderFlowThreadDisabler() { if (m_renderFlowThread) - m_view->setCurrentRenderFlowThread(m_renderFlowThread); + m_view->flowThreadController()->setCurrentRenderFlowThread(m_renderFlowThread); } private: RenderView* m_view; @@ -384,10 +201,10 @@ void RenderFlowThread::layout() continue; LayoutRect regionRect; if (isHorizontalWritingMode()) { - regionRect = LayoutRect(style()->direction() == LTR ? zeroLayoutUnit : logicalWidth() - region->contentWidth(), logicalHeight, region->contentWidth(), region->contentHeight()); + regionRect = LayoutRect(style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth() - region->contentWidth(), logicalHeight, region->contentWidth(), region->contentHeight()); logicalHeight += regionRect.height(); } else { - regionRect = LayoutRect(logicalHeight, style()->direction() == LTR ? zeroLayoutUnit : logicalWidth() - region->contentHeight(), region->contentWidth(), region->contentHeight()); + regionRect = LayoutRect(logicalHeight, style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth() - region->contentHeight(), region->contentWidth(), region->contentHeight()); logicalHeight += regionRect.width(); } region->setRegionRect(regionRect); @@ -399,6 +216,15 @@ void RenderFlowThread::layout() LayoutStateMaintainer statePusher(view(), this, regionsChanged); RenderBlock::layout(); statePusher.pop(); + if (document()->hasListenerType(Document::REGIONLAYOUTUPDATE_LISTENER) && !m_regionLayoutUpdateEventTimer.isActive()) + for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { + RenderRegion* region = *iter; + if (region->shouldDispatchRegionLayoutUpdateEvent()) { + // at least one region needs to dispatch the event + m_regionLayoutUpdateEventTimer.startOneShot(0); + break; + } + } } void RenderFlowThread::computeLogicalWidth() @@ -421,7 +247,7 @@ void RenderFlowThread::computeLogicalWidth() LayoutUnit regionLogicalWidth = isHorizontalWritingMode() ? region->contentWidth() : region->contentHeight(); if (regionLogicalWidth != logicalWidth) { - LayoutUnit logicalLeft = style()->direction() == LTR ? zeroLayoutUnit : logicalWidth - regionLogicalWidth; + LayoutUnit logicalLeft = style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth - regionLogicalWidth; region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth, false); } } @@ -429,7 +255,7 @@ void RenderFlowThread::computeLogicalWidth() void RenderFlowThread::computeLogicalHeight() { - int logicalHeight = 0; + LayoutUnit logicalHeight = 0; for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; @@ -676,7 +502,7 @@ void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box) } #ifndef NDEBUG - // We have to make sure we did not left any boxes with region info attached in regions. + // We have to make sure we did not leave any RenderBoxRegionInfo attached. for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) @@ -866,14 +692,6 @@ void RenderFlowThread::getRegionRangeForBox(const RenderBox* box, RenderRegion*& ASSERT(m_regionList.contains(startRegion) && m_regionList.contains(endRegion)); } -WebKitNamedFlow* RenderFlowThread::ensureNamedFlow() -{ - if (!m_namedFlow) - m_namedFlow = WebKitNamedFlow::create(this); - - return m_namedFlow.get(); -} - void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterEdge) { LayoutUnit height = oldClientAfterEdge; @@ -892,12 +710,20 @@ void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterE } LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x()); LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX()); + RenderRegion::RegionState previousState = region->regionState(); RenderRegion::RegionState state = RenderRegion::RegionFit; if (flowMin <= 0) state = RenderRegion::RegionEmpty; if (flowMax > 0) state = RenderRegion::RegionOverflow; region->setRegionState(state); + // determine whether this region should dispatch a regionLayoutUpdate event + // FIXME: currently it cannot determine whether a region whose regionOverflow state remained either "fit" or "overflow" has actually + // changed, so it just assumes that those region should dispatch the event + if (previousState != state + || state == RenderRegion::RegionFit + || state == RenderRegion::RegionOverflow) + region->setDispatchRegionLayoutUpdateEvent(true); } // With the regions overflow state computed we can also set the overflow for the named flow. @@ -905,6 +731,35 @@ void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterE m_overflow = lastReg && (lastReg->regionState() == RenderRegion::RegionOverflow); } +void RenderFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderFlowThread>*) +{ + // Create a copy of region nodes, to protect them for being destroyed in the event listener + Vector<RefPtr<Node> > regionNodes; + regionNodes.reserveCapacity(m_regionList.size()); + for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { + RenderRegion* region = *iter; + ASSERT(region->node() && region->node()->isElementNode()); + // dispatch the event only for marked regions and only for those who have a listener + if (region->shouldDispatchRegionLayoutUpdateEvent()) { + regionNodes.append(region->node()); + // clear the dispatch flag here, as it is possible to be set again due to event listeners + region->setDispatchRegionLayoutUpdateEvent(false); + } + } + for (Vector<RefPtr<Node> >::const_iterator it = regionNodes.begin(); it != regionNodes.end(); ++it) { + RefPtr<Node> node = *it; + RefPtr<Document> document = node->document(); + if (!document) + continue; + RenderObject* renderer = node->renderer(); + if (renderer && renderer->isRenderRegion()) { + node->dispatchRegionLayoutUpdateEvent(); + // Layout needs to be uptodate after each event listener + document->updateLayoutIgnorePendingStylesheets(); + } + } +} + bool RenderFlowThread::regionInRange(const RenderRegion* targetRegion, const RenderRegion* startRegion, const RenderRegion* endRegion) const { ASSERT(targetRegion); @@ -939,7 +794,7 @@ bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend RenderRegion* enclosingBoxEndRegion = 0; getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndRegion); if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion)) - return false; + return false; if (object->isBox()) return true; @@ -971,4 +826,3 @@ bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const Rend } } // namespace WebCore - |