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.
6 #include "public/web/WebFrame.h"
8 #include "bindings/core/v8/WindowProxyManager.h"
9 #include "core/frame/FrameHost.h"
10 #include "core/frame/FrameView.h"
11 #include "core/frame/LocalFrame.h"
12 #include "core/frame/RemoteFrame.h"
13 #include "core/html/HTMLFrameElementBase.h"
14 #include "core/html/HTMLFrameOwnerElement.h"
15 #include "core/page/Page.h"
16 #include "platform/UserGestureIndicator.h"
17 #include "platform/heap/Handle.h"
18 #include "public/web/WebElement.h"
19 #include "public/web/WebSandboxFlags.h"
20 #include "web/OpenedFrameTracker.h"
21 #include "web/RemoteBridgeFrameOwner.h"
22 #include "web/WebLocalFrameImpl.h"
23 #include "web/WebRemoteFrameImpl.h"
28 Frame
* toCoreFrame(const WebFrame
* frame
)
33 return frame
->isWebLocalFrame()
34 ? static_cast<Frame
*>(toWebLocalFrameImpl(frame
)->frame())
35 : toWebRemoteFrameImpl(frame
)->frame();
38 bool WebFrame::swap(WebFrame
* frame
)
41 RefPtrWillBeRawPtr
<Frame
> oldFrame
= toCoreFrame(this);
43 RefPtrWillBeRawPtr
<WebLocalFrameImpl
> protectWebLocalFrame
= isWebLocalFrame() ? toWebLocalFrameImpl(this) : nullptr;
44 RefPtrWillBeRawPtr
<WebRemoteFrameImpl
> protectWebRemoteFrame
= isWebRemoteFrame() ? toWebRemoteFrameImpl(this) : nullptr;
47 // Unload the current Document in this frame: this calls unload handlers,
48 // detaches child frames, etc. Since this runs script, make sure this frame
49 // wasn't detached before continuing with the swap.
50 // FIXME: There is no unit test for this condition, so one needs to be
52 if (!oldFrame
->prepareForCommit())
56 if (m_parent
->m_firstChild
== this)
57 m_parent
->m_firstChild
= frame
;
58 if (m_parent
->m_lastChild
== this)
59 m_parent
->m_lastChild
= frame
;
60 // FIXME: This is due to the fact that the |frame| may be a provisional
61 // local frame, because we don't know if the navigation will result in
62 // an actual page or something else, like a download. The PlzNavigate
63 // project will remove the need for provisional local frames.
64 frame
->m_parent
= m_parent
;
67 if (m_previousSibling
) {
68 m_previousSibling
->m_nextSibling
= frame
;
69 swap(m_previousSibling
, frame
->m_previousSibling
);
72 m_nextSibling
->m_previousSibling
= frame
;
73 swap(m_nextSibling
, frame
->m_nextSibling
);
77 m_opener
->m_openedFrameTracker
->remove(this);
78 m_opener
->m_openedFrameTracker
->add(frame
);
79 swap(m_opener
, frame
->m_opener
);
81 if (!m_openedFrameTracker
->isEmpty()) {
82 m_openedFrameTracker
->updateOpener(frame
);
83 frame
->m_openedFrameTracker
.reset(m_openedFrameTracker
.release());
86 // Finally, clone the state of the current Frame into one matching
87 // the type of the passed in WebFrame.
88 // FIXME: This is a bit clunky; this results in pointless decrements and
89 // increments of connected subframes.
90 FrameOwner
* owner
= oldFrame
->owner();
91 oldFrame
->disconnectOwnerElement();
92 if (frame
->isWebLocalFrame()) {
93 LocalFrame
& localFrame
= *toWebLocalFrameImpl(frame
)->frame();
94 ASSERT(owner
== localFrame
.owner());
96 if (owner
->isLocal()) {
97 HTMLFrameOwnerElement
* ownerElement
= toHTMLFrameOwnerElement(owner
);
98 ownerElement
->setContentFrame(localFrame
);
99 ownerElement
->setWidget(localFrame
.view());
101 toRemoteBridgeFrameOwner(owner
)->setContentFrame(toWebLocalFrameImpl(frame
));
104 localFrame
.page()->setMainFrame(&localFrame
);
107 toWebRemoteFrameImpl(frame
)->initializeCoreFrame(oldFrame
->host(), owner
, oldFrame
->tree().name());
109 toCoreFrame(frame
)->finishSwapFrom(oldFrame
.get());
111 // Although the Document in this frame is now unloaded, many resources
112 // associated with the frame itself have not yet been freed yet.
113 oldFrame
->detach(FrameDetachType::Swap
);
119 void WebFrame::detach()
121 toCoreFrame(this)->detach(FrameDetachType::Remove
);
124 WebSecurityOrigin
WebFrame::securityOrigin() const
126 return WebSecurityOrigin(toCoreFrame(this)->securityContext()->securityOrigin());
130 void WebFrame::setFrameOwnerSandboxFlags(WebSandboxFlags flags
)
132 // At the moment, this is only used to replicate sandbox flags
133 // for frames with a remote owner.
134 FrameOwner
* owner
= toCoreFrame(this)->owner();
136 toRemoteBridgeFrameOwner(owner
)->setSandboxFlags(static_cast<SandboxFlags
>(flags
));
139 WebFrame
* WebFrame::opener() const
144 void WebFrame::setOpener(WebFrame
* opener
)
147 m_opener
->m_openedFrameTracker
->remove(this);
149 opener
->m_openedFrameTracker
->add(this);
153 void WebFrame::insertAfter(WebFrame
* newChild
, WebFrame
* previousSibling
)
155 newChild
->m_parent
= this;
158 if (!previousSibling
) {
159 // Insert at the beginning if no previous sibling is specified.
161 m_firstChild
= newChild
;
163 ASSERT(previousSibling
->m_parent
== this);
164 next
= previousSibling
->m_nextSibling
;
165 previousSibling
->m_nextSibling
= newChild
;
166 newChild
->m_previousSibling
= previousSibling
;
170 newChild
->m_nextSibling
= next
;
171 next
->m_previousSibling
= newChild
;
173 m_lastChild
= newChild
;
176 toCoreFrame(this)->tree().invalidateScopedChildCount();
177 toCoreFrame(this)->host()->incrementSubframeCount();
180 void WebFrame::appendChild(WebFrame
* child
)
182 // TODO(dcheng): Original code asserts that the frames have the same Page.
183 // We should add an equivalent check... figure out what.
184 insertAfter(child
, m_lastChild
);
187 void WebFrame::removeChild(WebFrame
* child
)
191 if (m_firstChild
== child
)
192 m_firstChild
= child
->m_nextSibling
;
194 child
->m_previousSibling
->m_nextSibling
= child
->m_nextSibling
;
196 if (m_lastChild
== child
)
197 m_lastChild
= child
->m_previousSibling
;
199 child
->m_nextSibling
->m_previousSibling
= child
->m_previousSibling
;
201 child
->m_previousSibling
= child
->m_nextSibling
= 0;
203 toCoreFrame(this)->tree().invalidateScopedChildCount();
204 toCoreFrame(this)->host()->decrementSubframeCount();
207 void WebFrame::setParent(WebFrame
* parent
)
212 WebFrame
* WebFrame::parent() const
217 WebFrame
* WebFrame::top() const
219 WebFrame
* frame
= const_cast<WebFrame
*>(this);
220 for (WebFrame
* parent
= frame
; parent
; parent
= parent
->m_parent
)
225 WebFrame
* WebFrame::firstChild() const
230 WebFrame
* WebFrame::lastChild() const
235 WebFrame
* WebFrame::previousSibling() const
237 return m_previousSibling
;
240 WebFrame
* WebFrame::nextSibling() const
242 return m_nextSibling
;
245 WebFrame
* WebFrame::traversePrevious(bool wrap
) const
247 if (Frame
* frame
= toCoreFrame(this))
248 return fromFrame(frame
->tree().traversePreviousWithWrap(wrap
));
252 WebFrame
* WebFrame::traverseNext(bool wrap
) const
254 if (Frame
* frame
= toCoreFrame(this))
255 return fromFrame(frame
->tree().traverseNextWithWrap(wrap
));
259 WebFrame
* WebFrame::findChildByName(const WebString
& name
) const
261 Frame
* frame
= toCoreFrame(this);
264 // FIXME: It's not clear this should ever be called to find a remote frame.
265 // Perhaps just disallow that completely?
266 return fromFrame(frame
->tree().child(name
));
269 WebFrame
* WebFrame::fromFrameOwnerElement(const WebElement
& webElement
)
271 Element
* element
= PassRefPtrWillBeRawPtr
<Element
>(webElement
).get();
273 if (!isHTMLFrameElementBase(element
))
275 return fromFrame(toHTMLFrameElementBase(element
)->contentFrame());
278 WebFrame
* WebFrame::fromFrame(Frame
* frame
)
283 if (frame
->isLocalFrame())
284 return WebLocalFrameImpl::fromFrame(toLocalFrame(*frame
));
285 return WebRemoteFrameImpl::fromFrame(toRemoteFrame(*frame
));
288 WebFrame::WebFrame(WebTreeScopeType scope
)
291 , m_previousSibling(0)
296 , m_openedFrameTracker(new OpenedFrameTracker
)
300 WebFrame::~WebFrame()
302 m_openedFrameTracker
.reset(0);
306 ALWAYS_INLINE
bool WebFrame::isFrameAlive(const WebFrame
* frame
)
311 if (frame
->isWebLocalFrame())
312 return Heap::isHeapObjectAlive(toWebLocalFrameImpl(frame
));
314 return Heap::isHeapObjectAlive(toWebRemoteFrameImpl(frame
));
317 template <typename VisitorDispatcher
>
318 ALWAYS_INLINE
void WebFrame::traceFrameImpl(VisitorDispatcher visitor
, WebFrame
* frame
)
323 if (frame
->isWebLocalFrame())
324 visitor
->trace(toWebLocalFrameImpl(frame
));
326 visitor
->trace(toWebRemoteFrameImpl(frame
));
329 template <typename VisitorDispatcher
>
330 ALWAYS_INLINE
void WebFrame::traceFramesImpl(VisitorDispatcher visitor
, WebFrame
* frame
)
333 traceFrame(visitor
, frame
->m_parent
);
334 for (WebFrame
* child
= frame
->firstChild(); child
; child
= child
->nextSibling())
335 traceFrame(visitor
, child
);
336 // m_opener is a weak reference.
337 frame
->m_openedFrameTracker
->traceFrames(visitor
);
340 template <typename VisitorDispatcher
>
341 ALWAYS_INLINE
void WebFrame::clearWeakFramesImpl(VisitorDispatcher visitor
)
343 if (!isFrameAlive(m_opener
))
347 #define DEFINE_VISITOR_METHOD(VisitorDispatcher) \
348 void WebFrame::traceFrame(VisitorDispatcher visitor, WebFrame* frame) { traceFrameImpl(visitor, frame); } \
349 void WebFrame::traceFrames(VisitorDispatcher visitor, WebFrame* frame) { traceFramesImpl(visitor, frame); } \
350 void WebFrame::clearWeakFrames(VisitorDispatcher visitor) { clearWeakFramesImpl(visitor); }
352 DEFINE_VISITOR_METHOD(Visitor
*)
353 DEFINE_VISITOR_METHOD(InlinedGlobalMarkingVisitor
)
355 #undef DEFINE_VISITOR_METHOD