summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderFlowThread.cpp
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
committerSimon Hausmann <simon.hausmann@nokia.com>2012-05-07 11:21:11 +0200
commit2cf6c8816a73e0132bd8fa3b509d62d7c51b6e47 (patch)
tree988e8c5b116dd0466244ae2fe5af8ee9be926d76 /Source/WebCore/rendering/RenderFlowThread.cpp
parentdd91e772430dc294e3bf478c119ef8d43c0a3358 (diff)
downloadqtwebkit-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.cpp272
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
-