Use is<>() / downcast<>() for all remaining RenderObject subclasses
[WebKit-https.git] / Source / WebCore / dom / WebKitNamedFlow.cpp
index b157405..51dfc0b 100644 (file)
 #include "config.h"
 #include "WebKitNamedFlow.h"
 
-#include "Node.h"
-#include "NodeList.h"
-#include "RenderFlowThread.h"
+#include "NamedFlowCollection.h"
+#include "RenderNamedFlowFragment.h"
+#include "RenderNamedFlowThread.h"
 #include "RenderRegion.h"
 #include "StaticNodeList.h"
+#include "UIEvent.h"
 
 namespace WebCore {
 
-WebKitNamedFlow::WebKitNamedFlow(RenderFlowThread* parentFlowThread)
-: m_parentFlowThread(parentFlowThread)
+WebKitNamedFlow::WebKitNamedFlow(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
+    : m_flowThreadName(flowThreadName)
+    , m_flowManager(manager)
+    , m_parentFlowThread(nullptr)
 {
 }
 
 WebKitNamedFlow::~WebKitNamedFlow()
 {
+    // The named flow is not "strong" referenced from anywhere at this time so it shouldn't be reused if the named flow is recreated.
+    m_flowManager->discardNamedFlow(this);
 }
 
-bool WebKitNamedFlow::overflow() const
+PassRefPtr<WebKitNamedFlow> WebKitNamedFlow::create(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
 {
-    m_parentFlowThread->document()->updateLayoutIgnorePendingStylesheets();
-    return m_parentFlowThread->overflow();
+    return adoptRef(new WebKitNamedFlow(manager, flowThreadName));
 }
 
-PassRefPtr<NodeList> WebKitNamedFlow::contentNodes() const
+const AtomicString& WebKitNamedFlow::name() const
 {
-    m_parentFlowThread->document()->updateLayoutIgnorePendingStylesheets();
+    return m_flowThreadName;
+}
 
-    Vector<RefPtr<Node> > contentNodes;
-    for (NamedFlowContentNodes::const_iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) {
-        Node* node = const_cast<Node*>(*it);
-        ASSERT(node->computedStyle()->flowThread() == m_parentFlowThread->flowThread());
-        contentNodes.append(node);
-    }
+bool WebKitNamedFlow::overset() const
+{
+    if (m_flowManager->document())
+        m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
 
-    return StaticNodeList::adopt(contentNodes);
+    // The renderer may be destroyed or created after the style update.
+    // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
+    if (!m_parentFlowThread || !m_parentFlowThread->hasRegions())
+        return true;
+
+    const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*m_parentFlowThread->lastRegion());
+    return namedFlowFragment.regionOversetState() == RegionOverset;
 }
 
-// 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 orderer.
-void WebKitNamedFlow::registerContentNode(Node* contentNode)
+static inline bool inFlowThread(RenderObject* renderer, RenderNamedFlowThread* flowThread)
 {
-    ASSERT(contentNode && contentNode->isElementNode());
-
-    // 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;
-        }
+    if (!renderer)
+        return false;
+    RenderFlowThread* currentFlowThread = renderer->flowThreadContainingBlock();
+    if (flowThread == currentFlowThread)
+        return true;
+    if (renderer->flowThreadState() != RenderObject::InsideInFlowThread)
+        return false;
+    
+    // An in-flow flow thread can be nested inside an out-of-flow one, so we have to recur up to check.
+    return inFlowThread(currentFlowThread->containingBlock(), flowThread);
+}
+
+int WebKitNamedFlow::firstEmptyRegionIndex() const
+{
+    if (m_flowManager->document())
+        m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
+
+    if (!m_parentFlowThread)
+        return -1;
+
+    const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
+    if (regionList.isEmpty())
+        return -1;
+
+    int countNonPseudoRegions = -1;
+    for (const auto& renderRegion : regionList) {
+        const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*renderRegion);
+        // FIXME: Pseudo-elements are not included in the list.
+        // They will be included when we will properly support the Region interface
+        // http://dev.w3.org/csswg/css-regions/#the-region-interface
+        if (namedFlowFragment.isPseudoElementRegion())
+            continue;
+        ++countNonPseudoRegions;
+        if (namedFlowFragment.regionOversetState() == RegionEmpty)
+            return countNonPseudoRegions;
     }
-    m_contentNodes.add(contentNode);
+    return -1;
 }
 
-PassRefPtr<NodeList> WebKitNamedFlow::getRegionsByContentNode(Node* contentNode)
+PassRefPtr<NodeList> WebKitNamedFlow::getRegionsByContent(Node* contentNode)
 {
     if (!contentNode)
-        return 0;
+        return StaticElementList::createEmpty();
+
+    if (m_flowManager->document())
+        m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
+
+    // The renderer may be destroyed or created after the style update.
+    // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
+    if (!m_parentFlowThread)
+        return StaticElementList::createEmpty();
 
-    m_parentFlowThread->document()->updateLayoutIgnorePendingStylesheets();
+    Vector<Ref<Element>> regionElements;
 
-    Vector<RefPtr<Node> > regionNodes;
-    if (contentNode->renderer()
-        && contentNode->renderer()->inRenderFlowThread()
-        && m_parentFlowThread == contentNode->renderer()->enclosingRenderFlowThread()) {
+    if (inFlowThread(contentNode->renderer(), m_parentFlowThread)) {
         const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
-        for (RenderRegionList::const_iterator iter = regionList.begin(); iter != regionList.end(); ++iter) {
-            const RenderRegion* renderRegion = *iter;
-            if (!renderRegion->isValid())
+        for (const auto& renderRegion : regionList) {
+            const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*renderRegion);
+            // FIXME: Pseudo-elements are not included in the list.
+            // They will be included when we will properly support the Region interface
+            // http://dev.w3.org/csswg/css-regions/#the-region-interface
+            if (namedFlowFragment.isPseudoElementRegion())
                 continue;
-            if (m_parentFlowThread->objectInFlowRegion(contentNode->renderer(), renderRegion))
-                regionNodes.append(renderRegion->node());
+            if (m_parentFlowThread->objectInFlowRegion(contentNode->renderer(), &namedFlowFragment)) {
+                ASSERT(namedFlowFragment.generatingElement());
+                regionElements.append(*namedFlowFragment.generatingElement());
+            }
         }
     }
-    return StaticNodeList::adopt(regionNodes);
+
+    return StaticElementList::adopt(regionElements);
+}
+
+PassRefPtr<NodeList> WebKitNamedFlow::getRegions()
+{
+    if (m_flowManager->document())
+        m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
+
+    // The renderer may be destroyed or created after the style update.
+    // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
+    if (!m_parentFlowThread)
+        return StaticElementList::createEmpty();
+
+    Vector<Ref<Element>> regionElements;
+
+    const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
+    for (const auto& renderRegion : regionList) {
+        const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*renderRegion);
+        // FIXME: Pseudo-elements are not included in the list.
+        // They will be included when we will properly support the Region interface
+        // http://dev.w3.org/csswg/css-regions/#the-region-interface
+        if (namedFlowFragment.isPseudoElementRegion())
+            continue;
+        ASSERT(namedFlowFragment.generatingElement());
+        regionElements.append(*namedFlowFragment.generatingElement());
+    }
+
+    return StaticElementList::adopt(regionElements);
+}
+
+PassRefPtr<NodeList> WebKitNamedFlow::getContent()
+{
+    if (m_flowManager->document())
+        m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
+
+    // The renderer may be destroyed or created after the style update.
+    // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
+    if (!m_parentFlowThread)
+        return StaticElementList::createEmpty();
+
+    Vector<Ref<Element>> contentElements;
+
+    const NamedFlowContentElements& contentElementsList = m_parentFlowThread->contentElements();
+    for (auto& element : contentElementsList) {
+        ASSERT(element->computedStyle()->flowThread() == m_parentFlowThread->flowThreadName());
+        contentElements.append(*element);
+    }
+
+    return StaticElementList::adopt(contentElements);
+}
+
+void WebKitNamedFlow::setRenderer(RenderNamedFlowThread* parentFlowThread)
+{
+    // The named flow can either go from a no_renderer->renderer or renderer->no_renderer state; anything else could indicate a bug.
+    ASSERT((!m_parentFlowThread && parentFlowThread) || (m_parentFlowThread && !parentFlowThread));
+
+    // If parentFlowThread is 0, the flow thread will move in the "NULL" state.
+    m_parentFlowThread = parentFlowThread;
+}
+
+void WebKitNamedFlow::dispatchRegionOversetChangeEvent()
+{
+    ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
+    
+    // If the flow is in the "NULL" state the event should not be dispatched any more.
+    if (flowState() == FlowStateNull)
+        return;
+
+    dispatchEvent(UIEvent::create(eventNames().webkitregionoversetchangeEvent, false, false, m_flowManager->document()->defaultView(), 0));
+}
+
+ScriptExecutionContext* WebKitNamedFlow::scriptExecutionContext() const
+{
+    return m_flowManager->document();
+}
+
+Node* WebKitNamedFlow::ownerNode() const
+{
+    return m_flowManager->document();
 }
 
 } // namespace WebCore