RenderNamedFlowThread.cpp [plain text]
#include "config.h"
#include "RenderNamedFlowThread.h"
#include "FlowThreadController.h"
#include "RenderRegion.h"
#include "RenderView.h"
#include "WebKitNamedFlow.h"
namespace WebCore {
RenderNamedFlowThread::RenderNamedFlowThread(Node* node, const AtomicString& name)
: RenderFlowThread(node)
, m_flowThreadName(name)
{
}
const char* RenderNamedFlowThread::renderName() const
{
return "RenderNamedFlowThread";
}
RenderObject* RenderNamedFlowThread::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* RenderNamedFlowThread::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 RenderNamedFlowThread::addFlowChild(RenderObject* newChild, RenderObject* beforeChild)
{
if (!newChild->node())
return;
if (beforeChild)
m_flowThreadChildList.insertBefore(beforeChild, newChild);
else
m_flowThreadChildList.add(newChild);
}
void RenderNamedFlowThread::removeFlowChild(RenderObject* child)
{
m_flowThreadChildList.remove(child);
}
bool RenderNamedFlowThread::dependsOn(RenderNamedFlowThread* otherRenderFlowThread) const
{
if (m_layoutBeforeThreadsSet.contains(otherRenderFlowThread))
return true;
RenderNamedFlowThreadCountedSet::const_iterator iterator = m_layoutBeforeThreadsSet.begin();
RenderNamedFlowThreadCountedSet::const_iterator end = m_layoutBeforeThreadsSet.end();
for (; iterator != end; ++iterator) {
const RenderNamedFlowThread* beforeFlowThread = (*iterator).first;
if (beforeFlowThread->dependsOn(otherRenderFlowThread))
return true;
}
return false;
}
static bool compareRenderRegions(const RenderRegion* firstRegion, const RenderRegion* secondRegion)
{
ASSERT(firstRegion);
ASSERT(secondRegion);
ASSERT(firstRegion->node());
ASSERT(secondRegion->node());
unsigned short position = firstRegion->node()->compareDocumentPosition(secondRegion->node());
return (position & Node::DOCUMENT_POSITION_FOLLOWING);
}
void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
{
ASSERT(renderRegion);
if (m_regionList.isEmpty())
m_regionList.add(renderRegion);
else {
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->parentNamedFlowThread()) {
if (renderRegion->parentNamedFlowThread()->dependsOn(this)) {
renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this);
return;
}
addDependencyOnFlowThread(renderRegion->parentNamedFlowThread());
}
renderRegion->setIsValid(true);
invalidateRegions();
}
void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
{
ASSERT(renderRegion);
m_regionRangeMap.clear();
m_regionList.remove(renderRegion);
if (renderRegion->parentNamedFlowThread()) {
if (!renderRegion->isValid()) {
renderRegion->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
return;
}
removeDependencyOnFlowThread(renderRegion->parentNamedFlowThread());
}
invalidateRegions();
}
void RenderNamedFlowThread::checkInvalidRegions()
{
for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
RenderRegion* region = *iter;
ASSERT(region->isValid() || region->parentNamedFlowThread());
if (region->isValid() || region->parentNamedFlowThread()->dependsOn(this))
continue;
region->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
addDependencyOnFlowThread(region->parentNamedFlowThread());
region->setIsValid(true);
invalidateRegions();
}
if (m_observerThreadsSet.isEmpty())
return;
Vector<RenderNamedFlowThread*> observers;
copyToVector(m_observerThreadsSet, observers);
for (size_t i = 0; i < observers.size(); ++i) {
RenderNamedFlowThread* flowThread = observers.at(i);
flowThread->checkInvalidRegions();
}
}
void RenderNamedFlowThread::addDependencyOnFlowThread(RenderNamedFlowThread* otherFlowThread)
{
RenderNamedFlowThreadCountedSet::AddResult result = m_layoutBeforeThreadsSet.add(otherFlowThread);
if (result.isNewEntry) {
view()->flowThreadController()->setIsRenderNamedFlowThreadOrderDirty(true);
}
}
void RenderNamedFlowThread::removeDependencyOnFlowThread(RenderNamedFlowThread* otherFlowThread)
{
bool removed = m_layoutBeforeThreadsSet.remove(otherFlowThread);
if (removed) {
checkInvalidRegions();
view()->flowThreadController()->setIsRenderNamedFlowThreadOrderDirty(true);
}
}
void RenderNamedFlowThread::pushDependencies(RenderNamedFlowThreadList& list)
{
for (RenderNamedFlowThreadCountedSet::iterator iter = m_layoutBeforeThreadsSet.begin(); iter != m_layoutBeforeThreadsSet.end(); ++iter) {
RenderNamedFlowThread* flowThread = (*iter).first;
if (list.contains(flowThread))
continue;
flowThread->pushDependencies(list);
list.add(flowThread);
}
}
WebKitNamedFlow* RenderNamedFlowThread::ensureNamedFlow()
{
if (!m_namedFlow)
m_namedFlow = WebKitNamedFlow::create(this);
return m_namedFlow.get();
}
void RenderNamedFlowThread::registerNamedFlowContentNode(Node* contentNode)
{
ASSERT(contentNode && contentNode->isElementNode());
contentNode->setInNamedFlow();
for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) {
Node* node = *it;
unsigned short position = contentNode->compareDocumentPosition(node);
if (position & Node::DOCUMENT_POSITION_FOLLOWING) {
m_contentNodes.insertBefore(node, contentNode);
return;
}
}
m_contentNodes.add(contentNode);
}
void RenderNamedFlowThread::unregisterNamedFlowContentNode(Node* contentNode)
{
ASSERT(contentNode && contentNode->isElementNode());
ASSERT(m_contentNodes.contains(contentNode));
ASSERT(contentNode->inNamedFlow());
contentNode->clearInNamedFlow();
m_contentNodes.remove(contentNode);
}
}