void RenderNamedFlowThread::checkInvalidRegions()
{
    Vector<RenderNamedFlowFragment*> newValidFragments;
    for (auto& region : m_invalidRegionList) {
        RenderNamedFlowFragment* namedFlowFragment = toRenderNamedFlowFragment(region);
        // The only reason a region would be invalid is because it has a parent flow thread.
        ASSERT(!namedFlowFragment->isValid() && namedFlowFragment->parentNamedFlowThread());
        if (namedFlowFragment->parentNamedFlowThread()->dependsOn(this))
            continue;

        newValidFragments.append(namedFlowFragment);
    }

    for (auto& namedFlowFragment : newValidFragments) {
        m_invalidRegionList.remove(namedFlowFragment);
        namedFlowFragment->parentNamedFlowThread()->m_observerThreadsSet.remove(this);
        addFragmentToNamedFlowThread(namedFlowFragment);
    }

    if (!newValidFragments.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 (auto& flowThread : observers)
        flowThread->checkInvalidRegions();
}
Example #2
0
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const
{
    RenderRegion* startRegion = 0;
    RenderRegion* endRegion = 0;
    m_flowThread->getRegionRangeForBox(box, startRegion, endRegion);

    LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect);
    if (flowThread()->isHorizontalWritingMode()) {
        if (this != startRegion)
            mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y()));

        if (this != endRegion)
            mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height())));
    } else {
        if (this != startRegion)
            mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x()));
            
        if (this != endRegion)
            mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width())));
    }

    if (shouldClipFlowThreadContent()) {
        LayoutRect portionRect;
        if (isRenderNamedFlowFragment())
            portionRect = toRenderNamedFlowFragment(this)->flowThreadPortionRectForClipping(this == startRegion, this == endRegion);
        else
            portionRect = flowThreadPortionRect();
        
        mappedRect.intersect(portionRect);
    }

    return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect);
}
void RenderNamedFlowThread::clearRenderObjectCustomStyle(const RenderObject* object)
{
    // Clear the styles for the object in the regions.
    // FIXME: Region styling is not computed only for the region range of the object so this is why we need to walk the whole chain.
    for (auto& region : m_regionList)
        toRenderNamedFlowFragment(region)->clearObjectStyleInRegion(object);
}
void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion)
{
    ASSERT(renderRegion);

    RenderNamedFlowFragment* renderNamedFlowFragment = toRenderNamedFlowFragment(renderRegion);
    if (renderNamedFlowFragment->parentNamedFlowThread()) {
        if (!renderNamedFlowFragment->isValid()) {
            ASSERT(m_invalidRegionList.contains(renderNamedFlowFragment));
            m_invalidRegionList.remove(renderNamedFlowFragment);
            renderNamedFlowFragment->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(renderNamedFlowFragment->parentNamedFlowThread());
    }

    ASSERT(m_regionList.contains(renderNamedFlowFragment));
    bool wasFirst = m_regionList.first() == renderNamedFlowFragment;
    m_regionList.remove(renderNamedFlowFragment);

    if (canBeDestroyed())
        setMarkForDestruction();

    if (!m_regionList.isEmpty() && wasFirst)
        updateWritingMode();

    invalidateRegions();
}
// Check if the content is flown into at least a region with region styling rules.
void RenderNamedFlowThread::checkRegionsWithStyling()
{
    bool hasRegionsWithStyling = false;
    for (const auto& region : m_regionList) {
        if (toRenderNamedFlowFragment(region)->hasCustomRegionStyle()) {
            hasRegionsWithStyling = true;
            break;
        }
    }
    m_hasRegionsWithStyling = hasRegionsWithStyling;
}
void RenderNamedFlowThread::updateWritingMode()
{
    RenderNamedFlowFragment* firstFragment = toRenderNamedFlowFragment(m_regionList.first());
    if (!firstFragment)
        return;
    if (style().writingMode() == firstFragment->style().writingMode())
        return;

    // The first region defines the principal writing mode for the entire flow.
    auto newStyle = RenderStyle::clone(&style());
    newStyle.get().setWritingMode(firstFragment->style().writingMode());
    setStyle(WTF::move(newStyle));
}
RenderNamedFlowFragment* RenderNamedFlowThread::fragmentFromAbsolutePointAndBox(const IntPoint& absolutePoint, const RenderBox& flowedBox)
{
    RenderRegion* startRegion = nullptr;
    RenderRegion* endRegion = nullptr;
    if (!getRegionRangeForBox(&flowedBox, startRegion, endRegion))
        return nullptr;
    
    for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) {
        RenderNamedFlowFragment* fragment = toRenderNamedFlowFragment(*iter);
        RenderBlockFlow& fragmentContainer = fragment->fragmentContainer();
        IntRect fragmentAbsoluteRect(roundedIntPoint(fragmentContainer.localToAbsolute()), roundedIntSize(fragmentContainer.paddingBoxRect().size()));
        if (fragmentAbsoluteRect.contains(absolutePoint))
            return fragment;
        
        if (fragment == endRegion)
            break;
    }
    
    return nullptr;
}
void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion)
{
    ASSERT(renderRegion);
    ASSERT(!renderRegion->isValid());

    RenderNamedFlowFragment* renderNamedFlowFragment = toRenderNamedFlowFragment(renderRegion);
    resetMarkForDestruction();

    if (renderNamedFlowFragment->parentNamedFlowThread() && renderNamedFlowFragment->parentNamedFlowThread()->dependsOn(this)) {
        // The order of invalid regions is irrelevant.
        m_invalidRegionList.add(renderNamedFlowFragment);
        // Register ourself to get a notification when the state changes.
        renderNamedFlowFragment->parentNamedFlowThread()->m_observerThreadsSet.add(this);
        return;
    }

    addFragmentToNamedFlowThread(renderNamedFlowFragment);

    invalidateRegions();
}
// This helper function adds a region to a list preserving the order property of the list.
static void addFragmentToList(RenderRegionList& regionList, RenderNamedFlowFragment* renderNamedFlowFragment)
{
    if (regionList.isEmpty())
        regionList.add(renderNamedFlowFragment);
    else {
        // Find the first region "greater" than renderNamedFlowFragment.
        auto it = regionList.begin();
        while (it != regionList.end() && !compareRenderNamedFlowFragments(renderNamedFlowFragment, toRenderNamedFlowFragment(*it)))
            ++it;
        regionList.insertBefore(it, renderNamedFlowFragment);
    }
}