| Index: Source/core/rendering/RenderNamedFlowThread.cpp
 | 
| diff --git a/Source/core/rendering/RenderNamedFlowThread.cpp b/Source/core/rendering/RenderNamedFlowThread.cpp
 | 
| deleted file mode 100644
 | 
| index 72049543c9d3b0b88133850de3438ec70017ebfe..0000000000000000000000000000000000000000
 | 
| --- a/Source/core/rendering/RenderNamedFlowThread.cpp
 | 
| +++ /dev/null
 | 
| @@ -1,730 +0,0 @@
 | 
| -/*
 | 
| - * Copyright (C) 2012 Apple Inc.  All rights reserved.
 | 
| - *
 | 
| - * Redistribution and use in source and binary forms, with or without
 | 
| - * modification, are permitted provided that the following conditions
 | 
| - * are met:
 | 
| - * 1. Redistributions of source code must retain the above copyright
 | 
| - *    notice, this list of conditions and the following disclaimer.
 | 
| - * 2. Redistributions in binary form must reproduce the above copyright
 | 
| - *    notice, this list of conditions and the following disclaimer in the
 | 
| - *    documentation and/or other materials provided with the distribution.
 | 
| - *
 | 
| - * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 | 
| - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
| - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
| - * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 | 
| - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
| - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
| - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
| - * PROFITS; OR BUSINESS IN..0TERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | 
| - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
| - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
| - * OF THIS SOFTWARE, EVEN IF  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
| - */
 | 
| -
 | 
| -#include "config.h"
 | 
| -#include "core/rendering/RenderNamedFlowThread.h"
 | 
| -
 | 
| -#include "RuntimeEnabledFeatures.h"
 | 
| -#include "bindings/v8/ExceptionStatePlaceholder.h"
 | 
| -#include "core/dom/NamedFlow.h"
 | 
| -#include "core/dom/NodeRenderingTraversal.h"
 | 
| -#include "core/dom/NodeTraversal.h"
 | 
| -#include "core/dom/Position.h"
 | 
| -#include "core/dom/Range.h"
 | 
| -#include "core/dom/Text.h"
 | 
| -#include "core/inspector/InspectorInstrumentation.h"
 | 
| -#include "core/rendering/FlowThreadController.h"
 | 
| -#include "core/rendering/InlineTextBox.h"
 | 
| -#include "core/rendering/RenderInline.h"
 | 
| -#include "core/rendering/RenderRegion.h"
 | 
| -#include "core/rendering/RenderText.h"
 | 
| -#include "core/rendering/RenderView.h"
 | 
| -
 | 
| -namespace WebCore {
 | 
| -
 | 
| -RenderNamedFlowThread* RenderNamedFlowThread::createAnonymous(Document* document, PassRefPtr<NamedFlow> namedFlow)
 | 
| -{
 | 
| -    ASSERT(RuntimeEnabledFeatures::cssRegionsEnabled());
 | 
| -    RenderNamedFlowThread* renderer = new RenderNamedFlowThread(namedFlow);
 | 
| -    renderer->setDocumentForAnonymous(document);
 | 
| -    return renderer;
 | 
| -}
 | 
| -
 | 
| -RenderNamedFlowThread::RenderNamedFlowThread(PassRefPtr<NamedFlow> namedFlow)
 | 
| -    : m_overset(true)
 | 
| -    , m_namedFlow(namedFlow)
 | 
| -    , m_regionLayoutUpdateEventTimer(this, &RenderNamedFlowThread::regionLayoutUpdateEventTimerFired)
 | 
| -    , m_regionOversetChangeEventTimer(this, &RenderNamedFlowThread::regionOversetChangeEventTimerFired)
 | 
| -{
 | 
| -}
 | 
| -
 | 
| -RenderNamedFlowThread::~RenderNamedFlowThread()
 | 
| -{
 | 
| -    // The flow thread can be destroyed without unregistering the content nodes if the document is destroyed.
 | 
| -    // This can lead to problems because the nodes are still marked as belonging to a flow thread.
 | 
| -    clearContentNodes();
 | 
| -
 | 
| -    // Also leave the NamedFlow object in a consistent state by calling mark for destruction.
 | 
| -    setMarkForDestruction();
 | 
| -}
 | 
| -
 | 
| -const char* RenderNamedFlowThread::renderName() const
 | 
| -{
 | 
| -    return "RenderNamedFlowThread";
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::clearContentNodes()
 | 
| -{
 | 
| -    for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) {
 | 
| -        Node* contentNode = *it;
 | 
| -
 | 
| -        ASSERT(contentNode && contentNode->isElementNode());
 | 
| -        ASSERT(contentNode->inNamedFlow());
 | 
| -        ASSERT(contentNode->document() == document());
 | 
| -
 | 
| -        contentNode->clearInNamedFlow();
 | 
| -    }
 | 
| -
 | 
| -    m_contentNodes.clear();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::updateWritingMode()
 | 
| -{
 | 
| -    RenderRegion* firstRegion = m_regionList.first();
 | 
| -    if (!firstRegion)
 | 
| -        return;
 | 
| -    if (style()->writingMode() == firstRegion->style()->writingMode())
 | 
| -        return;
 | 
| -
 | 
| -    // The first region defines the principal writing mode for the entire flow.
 | 
| -    RefPtr<RenderStyle> newStyle = RenderStyle::clone(style());
 | 
| -    newStyle->setWritingMode(firstRegion->style()->writingMode());
 | 
| -    setStyle(newStyle.release());
 | 
| -}
 | 
| -
 | 
| -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)
 | 
| -{
 | 
| -    // 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.
 | 
| -
 | 
| -    Node* childNode = newChild->node();
 | 
| -
 | 
| -    // Do not add anonymous objects.
 | 
| -    if (!childNode)
 | 
| -        return;
 | 
| -
 | 
| -    ASSERT(childNode->isElementNode());
 | 
| -
 | 
| -    RenderObject* beforeChild = nextRendererForNode(childNode);
 | 
| -    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;
 | 
| -
 | 
| -    // Recursively traverse the m_layoutBeforeThreadsSet.
 | 
| -    RenderNamedFlowThreadCountedSet::const_iterator iterator = m_layoutBeforeThreadsSet.begin();
 | 
| -    RenderNamedFlowThreadCountedSet::const_iterator end = m_layoutBeforeThreadsSet.end();
 | 
| -    for (; iterator != end; ++iterator) {
 | 
| -        const RenderNamedFlowThread* beforeFlowThread = (*iterator).key;
 | 
| -        if (beforeFlowThread->dependsOn(otherRenderFlowThread))
 | 
| -            return true;
 | 
| -    }
 | 
| -
 | 
| -    return false;
 | 
| -}
 | 
| -
 | 
| -// 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);
 | 
| -
 | 
| -    ASSERT(firstRegion->generatingNodeForRegion());
 | 
| -    ASSERT(secondRegion->generatingNodeForRegion());
 | 
| -
 | 
| -    // If the regions belong to different nodes, compare their position in the DOM.
 | 
| -    if (firstRegion->generatingNodeForRegion() != secondRegion->generatingNodeForRegion()) {
 | 
| -        unsigned short position = firstRegion->generatingNodeForRegion()->compareDocumentPosition(secondRegion->generatingNodeForRegion());
 | 
| -
 | 
| -        // If the second region is contained in the first one, the first region is "less" if it's :before.
 | 
| -        if (position & Node::DOCUMENT_POSITION_CONTAINED_BY) {
 | 
| -            ASSERT(secondRegion->style()->styleType() == NOPSEUDO);
 | 
| -            return firstRegion->style()->styleType() == BEFORE;
 | 
| -        }
 | 
| -
 | 
| -        // If the second region contains the first region, the first region is "less" if the second is :after.
 | 
| -        if (position & Node::DOCUMENT_POSITION_CONTAINS) {
 | 
| -            ASSERT(firstRegion->style()->styleType() == NOPSEUDO);
 | 
| -            return secondRegion->style()->styleType() == AFTER;
 | 
| -        }
 | 
| -
 | 
| -        return (position & Node::DOCUMENT_POSITION_FOLLOWING);
 | 
| -    }
 | 
| -
 | 
| -    // FIXME: Currently it's not possible for an element to be both a region and have pseudo-children. The case is covered anyway.
 | 
| -    switch (firstRegion->style()->styleType()) {
 | 
| -    case BEFORE:
 | 
| -        // The second region can be the node or the after pseudo-element (before is smaller than any of those).
 | 
| -        return true;
 | 
| -    case AFTER:
 | 
| -        // The second region can be the node or the before pseudo-element (after is greater than any of those).
 | 
| -        return false;
 | 
| -    case NOPSEUDO:
 | 
| -        // The second region can either be the before or the after pseudo-element (the node is only smaller than the after pseudo-element).
 | 
| -        return firstRegion->style()->styleType() == AFTER;
 | 
| -    default:
 | 
| -        break;
 | 
| -    }
 | 
| -
 | 
| -    ASSERT_NOT_REACHED();
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
| -// This helper function adds a region to a list preserving the order property of the list.
 | 
| -static void addRegionToList(RenderRegionList& regionList, RenderRegion* renderRegion)
 | 
| -{
 | 
| -    if (regionList.isEmpty()) {
 | 
| -        regionList.add(renderRegion);
 | 
| -    } else {
 | 
| -        // Find the first region "greater" than renderRegion.
 | 
| -        RenderRegionList::iterator it = regionList.begin();
 | 
| -        while (it != regionList.end() && !compareRenderRegions(renderRegion, *it))
 | 
| -            ++it;
 | 
| -        regionList.insertBefore(it, renderRegion);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::addRegionToNamedFlowThread(RenderRegion* renderRegion)
 | 
| -{
 | 
| -    ASSERT(renderRegion);
 | 
| -    ASSERT(!renderRegion->isValid());
 | 
| -
 | 
| -    if (renderRegion->parentNamedFlowThread())
 | 
| -        addDependencyOnFlowThread(renderRegion->parentNamedFlowThread());
 | 
| -
 | 
| -    renderRegion->setIsValid(true);
 | 
| -    addRegionToList(m_regionList, renderRegion);
 | 
| -
 | 
| -    if (m_regionList.first() == renderRegion)
 | 
| -        updateWritingMode();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
 | 
| -{
 | 
| -    ASSERT(renderRegion);
 | 
| -    ASSERT(!renderRegion->isValid());
 | 
| -
 | 
| -    resetMarkForDestruction();
 | 
| -
 | 
| -    if (renderRegion->parentNamedFlowThread() && renderRegion->parentNamedFlowThread()->dependsOn(this)) {
 | 
| -        // The order of invalid regions is irrelevant.
 | 
| -        m_invalidRegionList.add(renderRegion);
 | 
| -        // Register ourself to get a notification when the state changes.
 | 
| -        renderRegion->parentNamedFlowThread()->m_observerThreadsSet.add(this);
 | 
| -        return;
 | 
| -    }
 | 
| -
 | 
| -    addRegionToNamedFlowThread(renderRegion);
 | 
| -
 | 
| -    invalidateRegions();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
 | 
| -{
 | 
| -    ASSERT(renderRegion);
 | 
| -
 | 
| -    if (renderRegion->parentNamedFlowThread()) {
 | 
| -        if (!renderRegion->isValid()) {
 | 
| -            ASSERT(m_invalidRegionList.contains(renderRegion));
 | 
| -            m_invalidRegionList.remove(renderRegion);
 | 
| -            renderRegion->parentNamedFlowThread()->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->parentNamedFlowThread());
 | 
| -    }
 | 
| -
 | 
| -    ASSERT(m_regionList.contains(renderRegion));
 | 
| -    bool wasFirst = m_regionList.first() == renderRegion;
 | 
| -    m_regionList.remove(renderRegion);
 | 
| -
 | 
| -    if (canBeDestroyed())
 | 
| -        setMarkForDestruction();
 | 
| -
 | 
| -    // After removing all the regions in the flow the following layout needs to dispatch the regionLayoutUpdate event
 | 
| -    if (m_regionList.isEmpty())
 | 
| -        setDispatchRegionLayoutUpdateEvent(true);
 | 
| -    else if (wasFirst)
 | 
| -        updateWritingMode();
 | 
| -
 | 
| -    invalidateRegions();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::regionChangedWritingMode(RenderRegion* region)
 | 
| -{
 | 
| -    if (m_regionList.first() == region)
 | 
| -        updateWritingMode();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::computeOversetStateForRegions(LayoutUnit oldClientAfterEdge)
 | 
| -{
 | 
| -    LayoutUnit height = oldClientAfterEdge;
 | 
| -
 | 
| -    // FIXME: the visual overflow of middle region (if it is the last one to contain any content in a render flow thread)
 | 
| -    // might not be taken into account because the render flow thread height is greater that that regions height + its visual overflow
 | 
| -    // because of how computeLogicalHeight is implemented for RenderFlowThread (as a sum of all regions height).
 | 
| -    // This means that the middle region will be marked as fit (even if it has visual overflow flowing into the next region)
 | 
| -    if (hasRenderOverflow()
 | 
| -        && ( (isHorizontalWritingMode() && visualOverflowRect().maxY() > clientBoxRect().maxY())
 | 
| -            || (!isHorizontalWritingMode() && visualOverflowRect().maxX() > clientBoxRect().maxX())))
 | 
| -        height = isHorizontalWritingMode() ? visualOverflowRect().maxY() : visualOverflowRect().maxX();
 | 
| -
 | 
| -    RenderRegion* lastReg = lastRegion();
 | 
| -    for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) {
 | 
| -        RenderRegion* region = *iter;
 | 
| -        LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x());
 | 
| -        LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX());
 | 
| -        RegionOversetState previousState = region->regionOversetState();
 | 
| -        RegionOversetState state = RegionFit;
 | 
| -        if (flowMin <= 0)
 | 
| -            state = RegionEmpty;
 | 
| -        if (flowMax > 0 && region == lastReg)
 | 
| -            state = RegionOverset;
 | 
| -        region->setRegionOversetState(state);
 | 
| -        // determine whether the NamedFlow object should dispatch a regionLayoutUpdate event
 | 
| -        // FIXME: currently it cannot determine whether a region whose regionOverset state remained either "fit" or "overset" has actually
 | 
| -        // changed, so it just assumes that the NamedFlow should dispatch the event
 | 
| -        if (previousState != state
 | 
| -            || state == RegionFit
 | 
| -            || state == RegionOverset)
 | 
| -            setDispatchRegionLayoutUpdateEvent(true);
 | 
| -
 | 
| -        if (previousState != state)
 | 
| -            setDispatchRegionOversetChangeEvent(true);
 | 
| -    }
 | 
| -
 | 
| -    // If the number of regions has changed since we last computed the overset property, schedule the regionOversetChange event.
 | 
| -    if (previousRegionCountChanged()) {
 | 
| -        setDispatchRegionOversetChangeEvent(true);
 | 
| -        updatePreviousRegionCount();
 | 
| -    }
 | 
| -
 | 
| -    // With the regions overflow state computed we can also set the overset flag for the named flow.
 | 
| -    // If there are no valid regions in the chain, overset is true.
 | 
| -    m_overset = lastReg ? lastReg->regionOversetState() == RegionOverset : true;
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::checkInvalidRegions()
 | 
| -{
 | 
| -    Vector<RenderRegion*> newValidRegions;
 | 
| -    for (RenderRegionList::iterator iter = m_invalidRegionList.begin(); iter != m_invalidRegionList.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->parentNamedFlowThread());
 | 
| -        if (region->parentNamedFlowThread()->dependsOn(this))
 | 
| -            continue;
 | 
| -
 | 
| -        newValidRegions.append(region);
 | 
| -    }
 | 
| -
 | 
| -    for (Vector<RenderRegion*>::iterator iter = newValidRegions.begin(); iter != newValidRegions.end(); ++iter) {
 | 
| -        RenderRegion* region = *iter;
 | 
| -        m_invalidRegionList.remove(region);
 | 
| -        region->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
 | 
| -        addRegionToNamedFlowThread(region);
 | 
| -    }
 | 
| -
 | 
| -    if (!newValidRegions.isEmpty())
 | 
| -        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<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) {
 | 
| -        // This is the first time we see this dependency. Make sure we recalculate all the dependencies.
 | 
| -        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).key;
 | 
| -        if (list.contains(flowThread))
 | 
| -            continue;
 | 
| -        flowThread->pushDependencies(list);
 | 
| -        list.add(flowThread);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -// The content nodes list contains those nodes with -webkit-flow-into: flow.
 | 
| -// An element with display:none should also be listed among those nodes.
 | 
| -// The list of nodes is ordered.
 | 
| -void RenderNamedFlowThread::registerNamedFlowContentNode(Node* contentNode)
 | 
| -{
 | 
| -    ASSERT(contentNode && contentNode->isElementNode());
 | 
| -    ASSERT(contentNode->document() == document());
 | 
| -
 | 
| -    contentNode->setInNamedFlow();
 | 
| -
 | 
| -    resetMarkForDestruction();
 | 
| -
 | 
| -    // Find the first content node following the new content node.
 | 
| -    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());
 | 
| -    ASSERT(contentNode->document() == document());
 | 
| -
 | 
| -    contentNode->clearInNamedFlow();
 | 
| -    m_contentNodes.remove(contentNode);
 | 
| -
 | 
| -    if (canBeDestroyed())
 | 
| -        setMarkForDestruction();
 | 
| -}
 | 
| -
 | 
| -const AtomicString& RenderNamedFlowThread::flowThreadName() const
 | 
| -{
 | 
| -    return m_namedFlow->name();
 | 
| -}
 | 
| -
 | 
| -bool RenderNamedFlowThread::isChildAllowed(RenderObject* child, RenderStyle* style) const
 | 
| -{
 | 
| -    if (!child->node())
 | 
| -        return true;
 | 
| -
 | 
| -    ASSERT(child->node()->isElementNode());
 | 
| -    Node* originalParent = NodeRenderingTraversal::parent(child->node());
 | 
| -    if (!originalParent || !originalParent->renderer())
 | 
| -        return true;
 | 
| -
 | 
| -    return originalParent->renderer()->isChildAllowed(child, style);
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::dispatchRegionLayoutUpdateEvent()
 | 
| -{
 | 
| -    RenderFlowThread::dispatchRegionLayoutUpdateEvent();
 | 
| -    InspectorInstrumentation::didUpdateRegionLayout(&document(), m_namedFlow.get());
 | 
| -
 | 
| -    if (!m_regionLayoutUpdateEventTimer.isActive() && m_namedFlow->hasEventListeners())
 | 
| -        m_regionLayoutUpdateEventTimer.startOneShot(0);
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::dispatchRegionOversetChangeEvent()
 | 
| -{
 | 
| -    RenderFlowThread::dispatchRegionOversetChangeEvent();
 | 
| -    InspectorInstrumentation::didChangeRegionOverset(&document(), m_namedFlow.get());
 | 
| -
 | 
| -    if (!m_regionOversetChangeEventTimer.isActive() && m_namedFlow->hasEventListeners())
 | 
| -        m_regionOversetChangeEventTimer.startOneShot(0);
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*)
 | 
| -{
 | 
| -    ASSERT(m_namedFlow);
 | 
| -
 | 
| -    m_namedFlow->dispatchRegionLayoutUpdateEvent();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::regionOversetChangeEventTimerFired(Timer<RenderNamedFlowThread>*)
 | 
| -{
 | 
| -    ASSERT(m_namedFlow);
 | 
| -
 | 
| -    m_namedFlow->dispatchRegionOversetChangeEvent();
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::setMarkForDestruction()
 | 
| -{
 | 
| -    if (m_namedFlow->flowState() == NamedFlow::FlowStateNull)
 | 
| -        return;
 | 
| -
 | 
| -    m_namedFlow->setRenderer(0);
 | 
| -    // After this call ends, the renderer can be safely destroyed.
 | 
| -    // The NamedFlow object may outlive its renderer if it's referenced from a script and may be reatached to one if the named flow is recreated in the stylesheet.
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::resetMarkForDestruction()
 | 
| -{
 | 
| -    if (m_namedFlow->flowState() == NamedFlow::FlowStateCreated)
 | 
| -        return;
 | 
| -
 | 
| -    m_namedFlow->setRenderer(this);
 | 
| -}
 | 
| -
 | 
| -bool RenderNamedFlowThread::isMarkedForDestruction() const
 | 
| -{
 | 
| -    // Flow threads in the "NULL" state can be destroyed.
 | 
| -    return m_namedFlow->flowState() == NamedFlow::FlowStateNull;
 | 
| -}
 | 
| -
 | 
| -static bool isContainedInNodes(Vector<Node*> others, Node* node)
 | 
| -{
 | 
| -    for (size_t i = 0; i < others.size(); i++) {
 | 
| -        Node* other = others.at(i);
 | 
| -        if (other->contains(node))
 | 
| -            return true;
 | 
| -    }
 | 
| -    return false;
 | 
| -}
 | 
| -
 | 
| -static bool boxIntersectsRegion(LayoutUnit logicalTopForBox, LayoutUnit logicalBottomForBox, LayoutUnit logicalTopForRegion, LayoutUnit logicalBottomForRegion)
 | 
| -{
 | 
| -    bool regionIsEmpty = logicalBottomForRegion != LayoutUnit::max() && logicalTopForRegion != LayoutUnit::min()
 | 
| -        && (logicalBottomForRegion - logicalTopForRegion) <= 0;
 | 
| -    return  (logicalBottomForBox - logicalTopForBox) > 0
 | 
| -        && !regionIsEmpty
 | 
| -        && logicalTopForBox < logicalBottomForRegion && logicalTopForRegion < logicalBottomForBox;
 | 
| -}
 | 
| -
 | 
| -// Retrieve the next node to be visited while computing the ranges inside a region.
 | 
| -static Node* nextNodeInsideContentNode(const Node& currNode, const Node* contentNode)
 | 
| -{
 | 
| -    ASSERT(contentNode && contentNode->inNamedFlow());
 | 
| -
 | 
| -    if (currNode.renderer() && currNode.renderer()->isSVGRoot())
 | 
| -        return NodeTraversal::nextSkippingChildren(currNode, contentNode);
 | 
| -    return NodeTraversal::next(currNode, contentNode);
 | 
| -}
 | 
| -
 | 
| -void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, const RenderRegion* region) const
 | 
| -{
 | 
| -    LayoutUnit logicalTopForRegion;
 | 
| -    LayoutUnit logicalBottomForRegion;
 | 
| -
 | 
| -    // extend the first region top to contain everything up to its logical height
 | 
| -    if (region->isFirstRegion())
 | 
| -        logicalTopForRegion = LayoutUnit::min();
 | 
| -    else
 | 
| -        logicalTopForRegion =  region->logicalTopForFlowThreadContent();
 | 
| -
 | 
| -    // extend the last region to contain everything above its y()
 | 
| -    if (region->isLastRegion())
 | 
| -        logicalBottomForRegion = LayoutUnit::max();
 | 
| -    else
 | 
| -        logicalBottomForRegion = region->logicalBottomForFlowThreadContent();
 | 
| -
 | 
| -    Vector<Node*> nodes;
 | 
| -    // eliminate the contentNodes that are descendants of other contentNodes
 | 
| -    for (NamedFlowContentNodes::const_iterator it = contentNodes().begin(); it != contentNodes().end(); ++it) {
 | 
| -        Node* node = *it;
 | 
| -        if (!isContainedInNodes(nodes, node))
 | 
| -            nodes.append(node);
 | 
| -    }
 | 
| -
 | 
| -    for (size_t i = 0; i < nodes.size(); i++) {
 | 
| -        Node* contentNode = nodes.at(i);
 | 
| -        if (!contentNode->renderer())
 | 
| -            continue;
 | 
| -
 | 
| -        RefPtr<Range> range = Range::create(contentNode->document());
 | 
| -        bool foundStartPosition = false;
 | 
| -        bool startsAboveRegion = true;
 | 
| -        bool endsBelowRegion = true;
 | 
| -        bool skipOverOutsideNodes = false;
 | 
| -        Node* lastEndNode = 0;
 | 
| -
 | 
| -        for (Node* node = contentNode; node; node = nextNodeInsideContentNode(*node, contentNode)) {
 | 
| -            RenderObject* renderer = node->renderer();
 | 
| -            if (!renderer)
 | 
| -                continue;
 | 
| -
 | 
| -            LayoutRect boundingBox;
 | 
| -            if (renderer->isRenderInline()) {
 | 
| -                boundingBox = toRenderInline(renderer)->linesBoundingBox();
 | 
| -            } else if (renderer->isText()) {
 | 
| -                boundingBox = toRenderText(renderer)->linesBoundingBox();
 | 
| -            } else {
 | 
| -                boundingBox =  toRenderBox(renderer)->frameRect();
 | 
| -                if (toRenderBox(renderer)->isRelPositioned())
 | 
| -                    boundingBox.move(toRenderBox(renderer)->relativePositionLogicalOffset());
 | 
| -            }
 | 
| -
 | 
| -            LayoutUnit offsetTop = renderer->containingBlock()->offsetFromLogicalTopOfFirstPage();
 | 
| -            const LayoutPoint logicalOffsetFromTop(isHorizontalWritingMode() ? LayoutUnit() :  offsetTop,
 | 
| -                isHorizontalWritingMode() ? offsetTop : LayoutUnit());
 | 
| -
 | 
| -            boundingBox.moveBy(logicalOffsetFromTop);
 | 
| -
 | 
| -            LayoutUnit logicalTopForRenderer = region->logicalTopOfFlowThreadContentRect(boundingBox);
 | 
| -            LayoutUnit logicalBottomForRenderer = region->logicalBottomOfFlowThreadContentRect(boundingBox);
 | 
| -
 | 
| -            // if the bounding box of the current element doesn't intersect the region box
 | 
| -            // close the current range only if the start element began inside the region,
 | 
| -            // otherwise just move the start position after this node and keep skipping them until we found a proper start position.
 | 
| -            if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) {
 | 
| -                if (foundStartPosition) {
 | 
| -                    if (!startsAboveRegion) {
 | 
| -                        if (range->intersectsNode(node, IGNORE_EXCEPTION))
 | 
| -                            range->setEndBefore(node, IGNORE_EXCEPTION);
 | 
| -                        rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION));
 | 
| -                        range = Range::create(contentNode->document());
 | 
| -                        startsAboveRegion = true;
 | 
| -                    } else {
 | 
| -                        skipOverOutsideNodes = true;
 | 
| -                    }
 | 
| -                }
 | 
| -                if (skipOverOutsideNodes)
 | 
| -                    range->setStartAfter(node, IGNORE_EXCEPTION);
 | 
| -                foundStartPosition = false;
 | 
| -                continue;
 | 
| -            }
 | 
| -
 | 
| -            // start position
 | 
| -            if (logicalTopForRenderer < logicalTopForRegion && startsAboveRegion) {
 | 
| -                if (renderer->isText()) { // Text crosses region top
 | 
| -                    // for Text elements, just find the last textbox that is contained inside the region and use its start() offset as start position
 | 
| -                    RenderText* textRenderer = toRenderText(renderer);
 | 
| -                    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
 | 
| -                        if (offsetTop + box->logicalBottom() < logicalTopForRegion)
 | 
| -                            continue;
 | 
| -                        range->setStart(Position(toText(node), box->start()));
 | 
| -                        startsAboveRegion = false;
 | 
| -                        break;
 | 
| -                    }
 | 
| -                } else { // node crosses region top
 | 
| -                    // for all elements, except Text, just set the start position to be before their children
 | 
| -                    startsAboveRegion = true;
 | 
| -                    range->setStart(Position(node, Position::PositionIsBeforeChildren));
 | 
| -                }
 | 
| -            } else { // node starts inside region
 | 
| -                // for elements that start inside the region, set the start position to be before them. If we found one, we will just skip the others until
 | 
| -                // the range is closed.
 | 
| -                if (startsAboveRegion) {
 | 
| -                    startsAboveRegion = false;
 | 
| -                    range->setStartBefore(node, IGNORE_EXCEPTION);
 | 
| -                }
 | 
| -            }
 | 
| -            skipOverOutsideNodes  = false;
 | 
| -            foundStartPosition = true;
 | 
| -
 | 
| -            // end position
 | 
| -            if (logicalBottomForRegion < logicalBottomForRenderer && (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode)))) {
 | 
| -                // for Text elements, just find just find the last textbox that is contained inside the region and use its start()+len() offset as end position
 | 
| -                if (renderer->isText()) { // Text crosses region bottom
 | 
| -                    RenderText* textRenderer = toRenderText(renderer);
 | 
| -                    InlineTextBox* lastBox = 0;
 | 
| -                    for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
 | 
| -                        if ((offsetTop + box->logicalTop()) < logicalBottomForRegion) {
 | 
| -                            lastBox = box;
 | 
| -                            continue;
 | 
| -                        }
 | 
| -                        ASSERT(lastBox);
 | 
| -                        if (lastBox)
 | 
| -                            range->setEnd(Position(toText(node), lastBox->start() + lastBox->len()));
 | 
| -                        break;
 | 
| -                    }
 | 
| -                    endsBelowRegion = false;
 | 
| -                    lastEndNode = node;
 | 
| -                } else { // node crosses region bottom
 | 
| -                    // for all elements, except Text, just set the start position to be after their children
 | 
| -                    range->setEnd(Position(node, Position::PositionIsAfterChildren));
 | 
| -                    endsBelowRegion = true;
 | 
| -                    lastEndNode = node;
 | 
| -                }
 | 
| -            } else { // node ends inside region
 | 
| -                // for elements that ends inside the region, set the end position to be after them
 | 
| -                // allow this end position to be changed only by other elements that are not descendants of the current end node
 | 
| -                if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) {
 | 
| -                    range->setEndAfter(node, IGNORE_EXCEPTION);
 | 
| -                    endsBelowRegion = false;
 | 
| -                    lastEndNode = node;
 | 
| -                }
 | 
| -            }
 | 
| -        }
 | 
| -        if (foundStartPosition || skipOverOutsideNodes)
 | 
| -            rangeObjects.append(range);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -}
 | 
| 
 |