1 /*
2 * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21 #include "config.h"
22 #include "core/html/HTMLFrameOwnerElement.h"
23
24 #include "bindings/core/v8/ExceptionMessages.h"
25 #include "bindings/core/v8/ExceptionState.h"
26 #include "core/accessibility/AXObjectCache.h"
27 #include "core/dom/ExceptionCode.h"
28 #include "core/events/Event.h"
29 #include "core/frame/FrameView.h"
30 #include "core/frame/LocalFrame.h"
31 #include "core/loader/FrameLoader.h"
32 #include "core/loader/FrameLoaderClient.h"
33 #include "core/rendering/RenderLayer.h"
34 #include "core/rendering/RenderPart.h"
35 #include "core/rendering/compositing/RenderLayerCompositor.h"
36 #include "platform/weborigin/SecurityOrigin.h"
37 #include "platform/weborigin/SecurityPolicy.h"
38
39 namespace blink {
40
41 typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap;
widgetNewParentMap()42 static WidgetToParentMap& widgetNewParentMap()
43 {
44 DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ());
45 return map;
46 }
47
disabledSubtreeRoots()48 WillBeHeapHashCountedSet<RawPtrWillBeMember<Node> >& SubframeLoadingDisabler::disabledSubtreeRoots()
49 {
50 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WillBeHeapHashCountedSet<RawPtrWillBeMember<Node> > >, nodes, (adoptPtrWillBeNoop(new WillBeHeapHashCountedSet<RawPtrWillBeMember<Node> >())));
51 return *nodes;
52 }
53
54 static unsigned s_updateSuspendCount = 0;
55
UpdateSuspendScope()56 HTMLFrameOwnerElement::UpdateSuspendScope::UpdateSuspendScope()
57 {
58 ++s_updateSuspendCount;
59 }
60
performDeferredWidgetTreeOperations()61 void HTMLFrameOwnerElement::UpdateSuspendScope::performDeferredWidgetTreeOperations()
62 {
63 WidgetToParentMap map;
64 widgetNewParentMap().swap(map);
65 WidgetToParentMap::iterator end = map.end();
66 for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) {
67 Widget* child = it->key.get();
68 ScrollView* currentParent = toScrollView(child->parent());
69 FrameView* newParent = it->value;
70 if (newParent != currentParent) {
71 if (currentParent)
72 currentParent->removeChild(child);
73 if (newParent)
74 newParent->addChild(child);
75 }
76 }
77 }
78
~UpdateSuspendScope()79 HTMLFrameOwnerElement::UpdateSuspendScope::~UpdateSuspendScope()
80 {
81 ASSERT(s_updateSuspendCount > 0);
82 if (s_updateSuspendCount == 1)
83 performDeferredWidgetTreeOperations();
84 --s_updateSuspendCount;
85 }
86
moveWidgetToParentSoon(Widget * child,FrameView * parent)87 static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
88 {
89 if (!s_updateSuspendCount) {
90 if (parent)
91 parent->addChild(child);
92 else if (toScrollView(child->parent()))
93 toScrollView(child->parent())->removeChild(child);
94 return;
95 }
96 widgetNewParentMap().set(child, parent);
97 }
98
HTMLFrameOwnerElement(const QualifiedName & tagName,Document & document)99 HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document& document)
100 : HTMLElement(tagName, document)
101 , m_contentFrame(nullptr)
102 , m_widget(nullptr)
103 , m_sandboxFlags(SandboxNone)
104 {
105 }
106
renderPart() const107 RenderPart* HTMLFrameOwnerElement::renderPart() const
108 {
109 // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
110 // when using fallback content.
111 if (!renderer() || !renderer()->isRenderPart())
112 return 0;
113 return toRenderPart(renderer());
114 }
115
setContentFrame(Frame & frame)116 void HTMLFrameOwnerElement::setContentFrame(Frame& frame)
117 {
118 // Make sure we will not end up with two frames referencing the same owner element.
119 ASSERT(!m_contentFrame || m_contentFrame->owner() != this);
120 // Disconnected frames should not be allowed to load.
121 ASSERT(inDocument());
122 m_contentFrame = &frame;
123
124 for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
125 node->incrementConnectedSubframeCount();
126 }
127
clearContentFrame()128 void HTMLFrameOwnerElement::clearContentFrame()
129 {
130 if (!m_contentFrame)
131 return;
132
133 m_contentFrame = nullptr;
134
135 for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
136 node->decrementConnectedSubframeCount();
137 }
138
disconnectContentFrame()139 void HTMLFrameOwnerElement::disconnectContentFrame()
140 {
141 // FIXME: Currently we don't do this in removedFrom because this causes an
142 // unload event in the subframe which could execute script that could then
143 // reach up into this document and then attempt to look back down. We should
144 // see if this behavior is really needed as Gecko does not allow this.
145 if (RefPtrWillBeRawPtr<Frame> frame = contentFrame()) {
146 frame->detach();
147 #if ENABLE(OILPAN)
148 // FIXME: Oilpan: the plugin container is released and finalized here
149 // in order to work around the current inability to make the plugin
150 // container a FrameDestructionObserver (it needs to effectively be on
151 // the heap, and Widget isn't). Hence, release it here while its
152 // frame reference is still valid.
153 if (m_widget && m_widget->isPluginContainer())
154 m_widget = nullptr;
155 #endif
156 frame->disconnectOwnerElement();
157 }
158 }
159
~HTMLFrameOwnerElement()160 HTMLFrameOwnerElement::~HTMLFrameOwnerElement()
161 {
162 #if ENABLE(OILPAN)
163 // An owner must by now have been informed of detachment
164 // when the frame was closed.
165 ASSERT(!m_contentFrame);
166 #else
167 if (m_contentFrame)
168 m_contentFrame->disconnectOwnerElement();
169 #endif
170 }
171
contentDocument() const172 Document* HTMLFrameOwnerElement::contentDocument() const
173 {
174 return (m_contentFrame && m_contentFrame->isLocalFrame()) ? toLocalFrame(m_contentFrame)->document() : 0;
175 }
176
contentWindow() const177 LocalDOMWindow* HTMLFrameOwnerElement::contentWindow() const
178 {
179 return m_contentFrame ? m_contentFrame->domWindow() : 0;
180 }
181
setSandboxFlags(SandboxFlags flags)182 void HTMLFrameOwnerElement::setSandboxFlags(SandboxFlags flags)
183 {
184 m_sandboxFlags = flags;
185 }
186
isKeyboardFocusable() const187 bool HTMLFrameOwnerElement::isKeyboardFocusable() const
188 {
189 return m_contentFrame && HTMLElement::isKeyboardFocusable();
190 }
191
dispatchLoad()192 void HTMLFrameOwnerElement::dispatchLoad()
193 {
194 dispatchEvent(Event::create(EventTypeNames::load));
195 }
196
getSVGDocument(ExceptionState & exceptionState) const197 Document* HTMLFrameOwnerElement::getSVGDocument(ExceptionState& exceptionState) const
198 {
199 Document* doc = contentDocument();
200 if (doc && doc->isSVGDocument())
201 return doc;
202 return 0;
203 }
204
setWidget(PassRefPtr<Widget> widget)205 void HTMLFrameOwnerElement::setWidget(PassRefPtr<Widget> widget)
206 {
207 if (widget == m_widget)
208 return;
209
210 if (m_widget) {
211 if (m_widget->parent())
212 moveWidgetToParentSoon(m_widget.get(), 0);
213 m_widget = nullptr;
214 }
215
216 m_widget = widget;
217
218 RenderWidget* renderWidget = toRenderWidget(renderer());
219 if (!renderWidget)
220 return;
221
222 if (m_widget) {
223 renderWidget->updateOnWidgetChange();
224
225 ASSERT(document().view() == renderWidget->frameView());
226 ASSERT(renderWidget->frameView());
227 moveWidgetToParentSoon(m_widget.get(), renderWidget->frameView());
228 }
229
230 if (AXObjectCache* cache = document().existingAXObjectCache())
231 cache->childrenChanged(renderWidget);
232 }
233
ownedWidget() const234 Widget* HTMLFrameOwnerElement::ownedWidget() const
235 {
236 return m_widget.get();
237 }
238
loadOrRedirectSubframe(const KURL & url,const AtomicString & frameName,bool lockBackForwardList)239 bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const AtomicString& frameName, bool lockBackForwardList)
240 {
241 RefPtrWillBeRawPtr<LocalFrame> parentFrame = document().frame();
242 // FIXME(kenrb): The necessary semantics for RemoteFrames have not been worked out yet, but this will likely need some logic to handle them.
243 if (contentFrame() && contentFrame()->isLocalFrame()) {
244 toLocalFrame(contentFrame())->navigationScheduler().scheduleLocationChange(&document(), url.string(), Referrer(document().outgoingReferrer(), document().referrerPolicy()), lockBackForwardList);
245 return true;
246 }
247
248 if (!document().securityOrigin()->canDisplay(url)) {
249 FrameLoader::reportLocalLoadFailed(parentFrame.get(), url.string());
250 return false;
251 }
252
253 if (!SubframeLoadingDisabler::canLoadFrame(*this))
254 return false;
255
256 String referrer = SecurityPolicy::generateReferrerHeader(document().referrerPolicy(), url, document().outgoingReferrer());
257 return parentFrame->loader().client()->createFrame(url, frameName, Referrer(referrer, document().referrerPolicy()), this);
258 }
259
trace(Visitor * visitor)260 void HTMLFrameOwnerElement::trace(Visitor* visitor)
261 {
262 visitor->trace(m_contentFrame);
263 HTMLElement::trace(visitor);
264 FrameOwner::trace(visitor);
265 }
266
267
268 } // namespace blink
269