Use is<>() / downcast<>() for all remaining RenderObject subclasses
[WebKit-https.git] / Source / WebCore / dom / WebKitNamedFlow.cpp
1 /*
2  * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "WebKitNamedFlow.h"
32
33 #include "NamedFlowCollection.h"
34 #include "RenderNamedFlowFragment.h"
35 #include "RenderNamedFlowThread.h"
36 #include "RenderRegion.h"
37 #include "StaticNodeList.h"
38 #include "UIEvent.h"
39
40 namespace WebCore {
41
42 WebKitNamedFlow::WebKitNamedFlow(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
43     : m_flowThreadName(flowThreadName)
44     , m_flowManager(manager)
45     , m_parentFlowThread(nullptr)
46 {
47 }
48
49 WebKitNamedFlow::~WebKitNamedFlow()
50 {
51     // The named flow is not "strong" referenced from anywhere at this time so it shouldn't be reused if the named flow is recreated.
52     m_flowManager->discardNamedFlow(this);
53 }
54
55 PassRefPtr<WebKitNamedFlow> WebKitNamedFlow::create(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
56 {
57     return adoptRef(new WebKitNamedFlow(manager, flowThreadName));
58 }
59
60 const AtomicString& WebKitNamedFlow::name() const
61 {
62     return m_flowThreadName;
63 }
64
65 bool WebKitNamedFlow::overset() const
66 {
67     if (m_flowManager->document())
68         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
69
70     // The renderer may be destroyed or created after the style update.
71     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
72     if (!m_parentFlowThread || !m_parentFlowThread->hasRegions())
73         return true;
74
75     const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*m_parentFlowThread->lastRegion());
76     return namedFlowFragment.regionOversetState() == RegionOverset;
77 }
78
79 static inline bool inFlowThread(RenderObject* renderer, RenderNamedFlowThread* flowThread)
80 {
81     if (!renderer)
82         return false;
83     RenderFlowThread* currentFlowThread = renderer->flowThreadContainingBlock();
84     if (flowThread == currentFlowThread)
85         return true;
86     if (renderer->flowThreadState() != RenderObject::InsideInFlowThread)
87         return false;
88     
89     // An in-flow flow thread can be nested inside an out-of-flow one, so we have to recur up to check.
90     return inFlowThread(currentFlowThread->containingBlock(), flowThread);
91 }
92
93 int WebKitNamedFlow::firstEmptyRegionIndex() const
94 {
95     if (m_flowManager->document())
96         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
97
98     if (!m_parentFlowThread)
99         return -1;
100
101     const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
102     if (regionList.isEmpty())
103         return -1;
104
105     int countNonPseudoRegions = -1;
106     for (const auto& renderRegion : regionList) {
107         const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*renderRegion);
108         // FIXME: Pseudo-elements are not included in the list.
109         // They will be included when we will properly support the Region interface
110         // http://dev.w3.org/csswg/css-regions/#the-region-interface
111         if (namedFlowFragment.isPseudoElementRegion())
112             continue;
113         ++countNonPseudoRegions;
114         if (namedFlowFragment.regionOversetState() == RegionEmpty)
115             return countNonPseudoRegions;
116     }
117     return -1;
118 }
119
120 PassRefPtr<NodeList> WebKitNamedFlow::getRegionsByContent(Node* contentNode)
121 {
122     if (!contentNode)
123         return StaticElementList::createEmpty();
124
125     if (m_flowManager->document())
126         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
127
128     // The renderer may be destroyed or created after the style update.
129     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
130     if (!m_parentFlowThread)
131         return StaticElementList::createEmpty();
132
133     Vector<Ref<Element>> regionElements;
134
135     if (inFlowThread(contentNode->renderer(), m_parentFlowThread)) {
136         const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
137         for (const auto& renderRegion : regionList) {
138             const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*renderRegion);
139             // FIXME: Pseudo-elements are not included in the list.
140             // They will be included when we will properly support the Region interface
141             // http://dev.w3.org/csswg/css-regions/#the-region-interface
142             if (namedFlowFragment.isPseudoElementRegion())
143                 continue;
144             if (m_parentFlowThread->objectInFlowRegion(contentNode->renderer(), &namedFlowFragment)) {
145                 ASSERT(namedFlowFragment.generatingElement());
146                 regionElements.append(*namedFlowFragment.generatingElement());
147             }
148         }
149     }
150
151     return StaticElementList::adopt(regionElements);
152 }
153
154 PassRefPtr<NodeList> WebKitNamedFlow::getRegions()
155 {
156     if (m_flowManager->document())
157         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
158
159     // The renderer may be destroyed or created after the style update.
160     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
161     if (!m_parentFlowThread)
162         return StaticElementList::createEmpty();
163
164     Vector<Ref<Element>> regionElements;
165
166     const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
167     for (const auto& renderRegion : regionList) {
168         const auto& namedFlowFragment = downcast<RenderNamedFlowFragment>(*renderRegion);
169         // FIXME: Pseudo-elements are not included in the list.
170         // They will be included when we will properly support the Region interface
171         // http://dev.w3.org/csswg/css-regions/#the-region-interface
172         if (namedFlowFragment.isPseudoElementRegion())
173             continue;
174         ASSERT(namedFlowFragment.generatingElement());
175         regionElements.append(*namedFlowFragment.generatingElement());
176     }
177
178     return StaticElementList::adopt(regionElements);
179 }
180
181 PassRefPtr<NodeList> WebKitNamedFlow::getContent()
182 {
183     if (m_flowManager->document())
184         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
185
186     // The renderer may be destroyed or created after the style update.
187     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
188     if (!m_parentFlowThread)
189         return StaticElementList::createEmpty();
190
191     Vector<Ref<Element>> contentElements;
192
193     const NamedFlowContentElements& contentElementsList = m_parentFlowThread->contentElements();
194     for (auto& element : contentElementsList) {
195         ASSERT(element->computedStyle()->flowThread() == m_parentFlowThread->flowThreadName());
196         contentElements.append(*element);
197     }
198
199     return StaticElementList::adopt(contentElements);
200 }
201
202 void WebKitNamedFlow::setRenderer(RenderNamedFlowThread* parentFlowThread)
203 {
204     // The named flow can either go from a no_renderer->renderer or renderer->no_renderer state; anything else could indicate a bug.
205     ASSERT((!m_parentFlowThread && parentFlowThread) || (m_parentFlowThread && !parentFlowThread));
206
207     // If parentFlowThread is 0, the flow thread will move in the "NULL" state.
208     m_parentFlowThread = parentFlowThread;
209 }
210
211 void WebKitNamedFlow::dispatchRegionOversetChangeEvent()
212 {
213     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
214     
215     // If the flow is in the "NULL" state the event should not be dispatched any more.
216     if (flowState() == FlowStateNull)
217         return;
218
219     dispatchEvent(UIEvent::create(eventNames().webkitregionoversetchangeEvent, false, false, m_flowManager->document()->defaultView(), 0));
220 }
221
222 ScriptExecutionContext* WebKitNamedFlow::scriptExecutionContext() const
223 {
224     return m_flowManager->document();
225 }
226
227 Node* WebKitNamedFlow::ownerNode() const
228 {
229     return m_flowManager->document();
230 }
231
232 } // namespace WebCore
233