29e8ae6e83aa8feaa7c2a280f59c8fbb0c171c13
[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 "EventNames.h"
34 #include "NamedFlowCollection.h"
35 #include "RenderNamedFlowFragment.h"
36 #include "RenderNamedFlowThread.h"
37 #include "RenderRegion.h"
38 #include "ScriptExecutionContext.h"
39 #include "StaticNodeList.h"
40 #include "UIEvent.h"
41
42 namespace WebCore {
43
44 WebKitNamedFlow::WebKitNamedFlow(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
45     : m_flowThreadName(flowThreadName)
46     , m_flowManager(manager)
47     , m_parentFlowThread(0)
48 {
49 }
50
51 WebKitNamedFlow::~WebKitNamedFlow()
52 {
53     // The named flow is not "strong" referenced from anywhere at this time so it shouldn't be reused if the named flow is recreated.
54     m_flowManager->discardNamedFlow(this);
55 }
56
57 PassRefPtr<WebKitNamedFlow> WebKitNamedFlow::create(PassRefPtr<NamedFlowCollection> manager, const AtomicString& flowThreadName)
58 {
59     return adoptRef(new WebKitNamedFlow(manager, flowThreadName));
60 }
61
62 const AtomicString& WebKitNamedFlow::name() const
63 {
64     return m_flowThreadName;
65 }
66
67 bool WebKitNamedFlow::overset() const
68 {
69     if (m_flowManager->document())
70         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
71
72     // The renderer may be destroyed or created after the style update.
73     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
74     return m_parentFlowThread ? m_parentFlowThread->overset() : true;
75 }
76
77 static inline bool inFlowThread(RenderObject* renderer, RenderNamedFlowThread* flowThread)
78 {
79     if (!renderer)
80         return false;
81     RenderFlowThread* currentFlowThread = renderer->flowThreadContainingBlock();
82     if (flowThread == currentFlowThread)
83         return true;
84     if (renderer->flowThreadState() != RenderObject::InsideInFlowThread)
85         return false;
86     
87     // An in-flow flow thread can be nested inside an out-of-flow one, so we have to recur up to check.
88     return inFlowThread(currentFlowThread->containingBlock(), flowThread);
89 }
90
91 int WebKitNamedFlow::firstEmptyRegionIndex() const
92 {
93     if (m_flowManager->document())
94         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
95
96     if (!m_parentFlowThread)
97         return -1;
98
99     const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
100     if (regionList.isEmpty())
101         return -1;
102
103     int countNonPseudoRegions = -1;
104     RenderRegionList::const_iterator iter = regionList.begin();
105     for (int index = 0; iter != regionList.end(); ++index, ++iter) {
106         // FIXME: Pseudo-elements are not included in the list.
107         // They will be included when we will properly support the Region interface
108         // http://dev.w3.org/csswg/css-regions/#the-region-interface
109         const RenderNamedFlowFragment* renderRegion = toRenderNamedFlowFragment(*iter);
110         if (renderRegion->isPseudoElementRegion())
111             continue;
112         countNonPseudoRegions++;
113         if (renderRegion->regionOversetState() == RegionEmpty)
114             return countNonPseudoRegions;
115     }
116     return -1;
117 }
118
119 PassRefPtr<NodeList> WebKitNamedFlow::getRegionsByContent(Node* contentNode)
120 {
121     if (!contentNode)
122         return StaticElementList::createEmpty();
123
124     if (m_flowManager->document())
125         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
126
127     // The renderer may be destroyed or created after the style update.
128     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
129     if (!m_parentFlowThread)
130         return StaticElementList::createEmpty();
131
132     Vector<Ref<Element>> regionElements;
133
134     if (inFlowThread(contentNode->renderer(), m_parentFlowThread)) {
135         const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
136         for (auto iter = regionList.begin(), end = regionList.end(); iter != end; ++iter) {
137             // FIXME: Pseudo-elements are not included in the list.
138             // They will be included when we will properly support the Region interface
139             // http://dev.w3.org/csswg/css-regions/#the-region-interface
140             const RenderNamedFlowFragment* renderRegion = toRenderNamedFlowFragment(*iter);
141             if (renderRegion->isPseudoElementRegion())
142                 continue;
143             if (m_parentFlowThread->objectInFlowRegion(contentNode->renderer(), renderRegion)) {
144                 ASSERT(renderRegion->generatingElement());
145                 regionElements.append(*renderRegion->generatingElement());
146             }
147         }
148     }
149
150     return StaticElementList::adopt(regionElements);
151 }
152
153 PassRefPtr<NodeList> WebKitNamedFlow::getRegions()
154 {
155     if (m_flowManager->document())
156         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
157
158     // The renderer may be destroyed or created after the style update.
159     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
160     if (!m_parentFlowThread)
161         return StaticElementList::createEmpty();
162
163     Vector<Ref<Element>> regionElements;
164
165     const RenderRegionList& regionList = m_parentFlowThread->renderRegionList();
166     for (auto iter = regionList.begin(), end = regionList.end(); iter != end; ++iter) {
167         // FIXME: Pseudo-elements are not included in the list.
168         // They will be included when we will properly support the Region interface
169         // http://dev.w3.org/csswg/css-regions/#the-region-interface
170         const RenderNamedFlowFragment* renderRegion = toRenderNamedFlowFragment(*iter);
171         if (renderRegion->isPseudoElementRegion())
172             continue;
173         ASSERT(renderRegion->generatingElement());
174         regionElements.append(*renderRegion->generatingElement());
175     }
176
177     return StaticElementList::adopt(regionElements);
178 }
179
180 PassRefPtr<NodeList> WebKitNamedFlow::getContent()
181 {
182     if (m_flowManager->document())
183         m_flowManager->document()->updateLayoutIgnorePendingStylesheets();
184
185     // The renderer may be destroyed or created after the style update.
186     // Because this is called from JS, where the wrapper keeps a reference to the NamedFlow, no guard is necessary.
187     if (!m_parentFlowThread)
188         return StaticElementList::createEmpty();
189
190     Vector<Ref<Element>> contentElements;
191
192     const NamedFlowContentElements& contentElementsList = m_parentFlowThread->contentElements();
193     for (auto it = contentElementsList.begin(), end = contentElementsList.end(); it != end; ++it) {
194         Element* element = *it;
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::dispatchRegionLayoutUpdateEvent()
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().webkitregionlayoutupdateEvent, false, false, m_flowManager->document()->defaultView(), 0));
220 }
221     
222 void WebKitNamedFlow::dispatchRegionOversetChangeEvent()
223 {
224     ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
225     
226     // If the flow is in the "NULL" state the event should not be dispatched any more.
227     if (flowState() == FlowStateNull)
228         return;
229
230     dispatchEvent(UIEvent::create(eventNames().webkitregionoversetchangeEvent, false, false, m_flowManager->document()->defaultView(), 0));
231 }
232
233 ScriptExecutionContext* WebKitNamedFlow::scriptExecutionContext() const
234 {
235     return m_flowManager->document();
236 }
237
238 Node* WebKitNamedFlow::ownerNode() const
239 {
240     return m_flowManager->document();
241 }
242
243 } // namespace WebCore
244