1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "config.h"
6 #include "public/web/WebFrame.h"
7
8 #include "core/frame/RemoteFrame.h"
9 #include "core/html/HTMLFrameOwnerElement.h"
10 #include "platform/UserGestureIndicator.h"
11 #include "platform/heap/Handle.h"
12 #include "web/OpenedFrameTracker.h"
13 #include "web/WebLocalFrameImpl.h"
14 #include "web/WebRemoteFrameImpl.h"
15 #include <algorithm>
16
17 namespace blink {
18
toCoreFrame(const WebFrame * frame)19 Frame* toCoreFrame(const WebFrame* frame)
20 {
21 if (!frame)
22 return 0;
23
24 return frame->isWebLocalFrame()
25 ? static_cast<Frame*>(toWebLocalFrameImpl(frame)->frame())
26 : toWebRemoteFrameImpl(frame)->frame();
27 }
28
swap(WebFrame * frame)29 bool WebFrame::swap(WebFrame* frame)
30 {
31 using std::swap;
32 RefPtrWillBeRawPtr<Frame> oldFrame = toCoreFrame(this);
33
34 // All child frames must be detached first.
35 oldFrame->detachChildren();
36
37 // If the frame has been detached during detaching its children, return
38 // immediately.
39 // FIXME: There is no unit test for this condition, so one needs to be
40 // written.
41 if (!oldFrame->host())
42 return false;
43
44 // The frame being swapped in should not have a Frame associated
45 // with it yet.
46 ASSERT(!toCoreFrame(frame));
47
48 if (m_parent) {
49 if (m_parent->m_firstChild == this)
50 m_parent->m_firstChild = frame;
51 if (m_parent->m_lastChild == this)
52 m_parent->m_lastChild = frame;
53 swap(m_parent, frame->m_parent);
54 }
55
56 if (m_previousSibling) {
57 m_previousSibling->m_nextSibling = frame;
58 swap(m_previousSibling, frame->m_previousSibling);
59 }
60 if (m_nextSibling) {
61 m_nextSibling->m_previousSibling = frame;
62 swap(m_nextSibling, frame->m_nextSibling);
63 }
64
65 if (m_opener) {
66 m_opener->m_openedFrameTracker->remove(this);
67 m_opener->m_openedFrameTracker->add(frame);
68 swap(m_opener, frame->m_opener);
69 }
70 if (!m_openedFrameTracker->isEmpty()) {
71 m_openedFrameTracker->updateOpener(frame);
72 frame->m_openedFrameTracker.reset(m_openedFrameTracker.release());
73 }
74
75 // Finally, clone the state of the current Frame into one matching
76 // the type of the passed in WebFrame.
77 // FIXME: This is a bit clunky; this results in pointless decrements and
78 // increments of connected subframes.
79 FrameOwner* owner = oldFrame->owner();
80 oldFrame->disconnectOwnerElement();
81 if (frame->isWebLocalFrame()) {
82 toWebLocalFrameImpl(frame)->initializeCoreFrame(oldFrame->host(), owner, oldFrame->tree().name(), nullAtom);
83 } else {
84 toWebRemoteFrameImpl(frame)->initializeCoreFrame(oldFrame->host(), owner, oldFrame->tree().name());
85 }
86
87 return true;
88 }
89
detach()90 void WebFrame::detach()
91 {
92 toCoreFrame(this)->detach();
93 }
94
opener() const95 WebFrame* WebFrame::opener() const
96 {
97 return m_opener;
98 }
99
setOpener(WebFrame * opener)100 void WebFrame::setOpener(WebFrame* opener)
101 {
102 if (m_opener)
103 m_opener->m_openedFrameTracker->remove(this);
104 if (opener)
105 opener->m_openedFrameTracker->add(this);
106 m_opener = opener;
107 }
108
appendChild(WebFrame * child)109 void WebFrame::appendChild(WebFrame* child)
110 {
111 // FIXME: Original code asserts that the frames have the same Page. We
112 // should add an equivalent check... figure out what.
113 child->m_parent = this;
114 WebFrame* oldLast = m_lastChild;
115 m_lastChild = child;
116
117 if (oldLast) {
118 child->m_previousSibling = oldLast;
119 oldLast->m_nextSibling = child;
120 } else {
121 m_firstChild = child;
122 }
123
124 toCoreFrame(this)->tree().invalidateScopedChildCount();
125 }
126
removeChild(WebFrame * child)127 void WebFrame::removeChild(WebFrame* child)
128 {
129 child->m_parent = 0;
130
131 if (m_firstChild == child)
132 m_firstChild = child->m_nextSibling;
133 else
134 child->m_previousSibling->m_nextSibling = child->m_nextSibling;
135
136 if (m_lastChild == child)
137 m_lastChild = child->m_previousSibling;
138 else
139 child->m_nextSibling->m_previousSibling = child->m_previousSibling;
140
141 child->m_previousSibling = child->m_nextSibling = 0;
142
143 toCoreFrame(this)->tree().invalidateScopedChildCount();
144 }
145
parent() const146 WebFrame* WebFrame::parent() const
147 {
148 return m_parent;
149 }
150
top() const151 WebFrame* WebFrame::top() const
152 {
153 WebFrame* frame = const_cast<WebFrame*>(this);
154 for (WebFrame* parent = frame; parent; parent = parent->m_parent)
155 frame = parent;
156 return frame;
157 }
158
firstChild() const159 WebFrame* WebFrame::firstChild() const
160 {
161 return m_firstChild;
162 }
163
lastChild() const164 WebFrame* WebFrame::lastChild() const
165 {
166 return m_lastChild;
167 }
168
previousSibling() const169 WebFrame* WebFrame::previousSibling() const
170 {
171 return m_previousSibling;
172 }
173
nextSibling() const174 WebFrame* WebFrame::nextSibling() const
175 {
176 return m_nextSibling;
177 }
178
traversePrevious(bool wrap) const179 WebFrame* WebFrame::traversePrevious(bool wrap) const
180 {
181 if (Frame* frame = toCoreFrame(this))
182 return fromFrame(frame->tree().traversePreviousWithWrap(wrap));
183 return 0;
184 }
185
traverseNext(bool wrap) const186 WebFrame* WebFrame::traverseNext(bool wrap) const
187 {
188 if (Frame* frame = toCoreFrame(this))
189 return fromFrame(frame->tree().traverseNextWithWrap(wrap));
190 return 0;
191 }
192
findChildByName(const WebString & name) const193 WebFrame* WebFrame::findChildByName(const WebString& name) const
194 {
195 Frame* frame = toCoreFrame(this);
196 if (!frame)
197 return 0;
198 // FIXME: It's not clear this should ever be called to find a remote frame.
199 // Perhaps just disallow that completely?
200 return fromFrame(frame->tree().child(name));
201 }
202
fromFrame(Frame * frame)203 WebFrame* WebFrame::fromFrame(Frame* frame)
204 {
205 if (!frame)
206 return 0;
207
208 if (frame->isLocalFrame())
209 return WebLocalFrameImpl::fromFrame(toLocalFrame(*frame));
210 return WebRemoteFrameImpl::fromFrame(toRemoteFrame(*frame));
211 }
212
WebFrame()213 WebFrame::WebFrame()
214 : m_parent(0)
215 , m_previousSibling(0)
216 , m_nextSibling(0)
217 , m_firstChild(0)
218 , m_lastChild(0)
219 , m_opener(0)
220 , m_openedFrameTracker(new OpenedFrameTracker)
221 {
222 }
223
~WebFrame()224 WebFrame::~WebFrame()
225 {
226 m_openedFrameTracker.reset(0);
227 }
228
traceChildren(Visitor * visitor,WebFrame * frame)229 void WebFrame::traceChildren(Visitor* visitor, WebFrame* frame)
230 {
231 #if ENABLE(OILPAN)
232 // Trace the children frames.
233 WebFrame* child = frame ? frame->firstChild() : 0;
234 while (child) {
235 if (child->isWebLocalFrame())
236 visitor->trace(toWebLocalFrameImpl(child));
237 else
238 visitor->trace(toWebRemoteFrameImpl(child));
239
240 child = child->nextSibling();
241 }
242 #endif
243 }
244
245 } // namespace blink
246