2 * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
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.
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.
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.
22 #include "core/html/HTMLFrameOwnerElement.h"
24 #include "bindings/v8/ExceptionMessages.h"
25 #include "bindings/v8/ExceptionState.h"
26 #include "core/accessibility/AXObjectCache.h"
27 #include "core/dom/ExceptionCode.h"
28 #include "core/frame/FrameView.h"
29 #include "core/frame/LocalFrame.h"
30 #include "core/loader/FrameLoader.h"
31 #include "core/loader/FrameLoaderClient.h"
32 #include "core/rendering/RenderLayer.h"
33 #include "core/rendering/RenderPart.h"
34 #include "core/rendering/compositing/RenderLayerCompositor.h"
35 #include "platform/weborigin/SecurityOrigin.h"
36 #include "platform/weborigin/SecurityPolicy.h"
40 typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap;
41 static WidgetToParentMap& widgetNewParentMap()
43 DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ());
47 static unsigned s_updateSuspendCount = 0;
49 HTMLFrameOwnerElement::UpdateSuspendScope::UpdateSuspendScope()
51 ++s_updateSuspendCount;
54 void HTMLFrameOwnerElement::UpdateSuspendScope::performDeferredWidgetTreeOperations()
56 WidgetToParentMap map;
57 widgetNewParentMap().swap(map);
58 WidgetToParentMap::iterator end = map.end();
59 for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) {
60 Widget* child = it->key.get();
61 ScrollView* currentParent = toScrollView(child->parent());
62 FrameView* newParent = it->value;
63 if (newParent != currentParent) {
65 currentParent->removeChild(child);
67 newParent->addChild(child);
72 HTMLFrameOwnerElement::UpdateSuspendScope::~UpdateSuspendScope()
74 ASSERT(s_updateSuspendCount > 0);
75 if (s_updateSuspendCount == 1)
76 performDeferredWidgetTreeOperations();
77 --s_updateSuspendCount;
80 static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
82 if (!s_updateSuspendCount) {
84 parent->addChild(child);
85 else if (toScrollView(child->parent()))
86 toScrollView(child->parent())->removeChild(child);
89 widgetNewParentMap().set(child, parent);
92 HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document& document)
93 : HTMLElement(tagName, document)
96 , m_sandboxFlags(SandboxNone)
100 RenderPart* HTMLFrameOwnerElement::renderPart() const
102 // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
103 // when using fallback content.
104 if (!renderer() || !renderer()->isRenderPart())
106 return toRenderPart(renderer());
109 void HTMLFrameOwnerElement::setContentFrame(Frame& frame)
111 // Make sure we will not end up with two frames referencing the same owner element.
112 ASSERT(!m_contentFrame || m_contentFrame->ownerElement() != this);
113 // Disconnected frames should not be allowed to load.
114 ASSERT(inDocument());
115 m_contentFrame = &frame;
117 for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
118 node->incrementConnectedSubframeCount();
121 void HTMLFrameOwnerElement::clearContentFrame()
128 for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
129 node->decrementConnectedSubframeCount();
132 void HTMLFrameOwnerElement::disconnectContentFrame()
134 // FIXME: Currently we don't do this in removedFrom because this causes an
135 // unload event in the subframe which could execute script that could then
136 // reach up into this document and then attempt to look back down. We should
137 // see if this behavior is really needed as Gecko does not allow this.
138 if (Frame* frame = contentFrame()) {
139 RefPtr<Frame> protect(frame);
140 if (frame->isLocalFrame())
141 toLocalFrame(frame)->loader().frameDetached();
142 frame->disconnectOwnerElement();
146 HTMLFrameOwnerElement::~HTMLFrameOwnerElement()
149 m_contentFrame->disconnectOwnerElement();
152 Document* HTMLFrameOwnerElement::contentDocument() const
154 return (m_contentFrame && m_contentFrame->isLocalFrame()) ? toLocalFrame(m_contentFrame)->document() : 0;
157 DOMWindow* HTMLFrameOwnerElement::contentWindow() const
159 return m_contentFrame ? m_contentFrame->domWindow() : 0;
162 void HTMLFrameOwnerElement::setSandboxFlags(SandboxFlags flags)
164 m_sandboxFlags = flags;
167 bool HTMLFrameOwnerElement::isKeyboardFocusable() const
169 return m_contentFrame && HTMLElement::isKeyboardFocusable();
172 Document* HTMLFrameOwnerElement::getSVGDocument(ExceptionState& exceptionState) const
174 Document* doc = contentDocument();
175 if (doc && doc->isSVGDocument())
180 void HTMLFrameOwnerElement::setWidget(PassRefPtr<Widget> widget)
182 if (widget == m_widget)
186 if (m_widget->parent())
187 moveWidgetToParentSoon(m_widget.get(), 0);
193 RenderWidget* renderWidget = toRenderWidget(renderer());
198 renderWidget->updateOnWidgetChange();
200 ASSERT(document().view() == renderWidget->frameView());
201 ASSERT(renderWidget->frameView());
202 moveWidgetToParentSoon(m_widget.get(), renderWidget->frameView());
205 if (AXObjectCache* cache = document().existingAXObjectCache())
206 cache->childrenChanged(renderWidget);
209 Widget* HTMLFrameOwnerElement::ownedWidget() const
211 return m_widget.get();
214 bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const AtomicString& frameName, bool lockBackForwardList)
216 RefPtr<LocalFrame> parentFrame = document().frame();
217 // FIXME(kenrb): The necessary semantics for RemoteFrames have not been worked out yet, but this will likely need some logic to handle them.
218 if (contentFrame() && contentFrame()->isLocalFrame()) {
219 toLocalFrame(contentFrame())->navigationScheduler().scheduleLocationChange(&document(), url.string(), Referrer(document().outgoingReferrer(), document().referrerPolicy()), lockBackForwardList);
223 if (!document().securityOrigin()->canDisplay(url)) {
224 FrameLoader::reportLocalLoadFailed(parentFrame.get(), url.string());
228 if (!SubframeLoadingDisabler::canLoadFrame(*this))
231 String referrer = SecurityPolicy::generateReferrerHeader(document().referrerPolicy(), url, document().outgoingReferrer());
232 RefPtr<LocalFrame> childFrame = parentFrame->loader().client()->createFrame(url, frameName, Referrer(referrer, document().referrerPolicy()), this);
235 parentFrame->loader().checkCompleted();
239 // All new frames will have m_isComplete set to true at this point due to synchronously loading
240 // an empty document in FrameLoader::init(). But many frames will now be starting an
241 // asynchronous load of url, so we set m_isComplete to false and then check if the load is
242 // actually completed below. (Note that we set m_isComplete to false even for synchronous
243 // loads, so that checkCompleted() below won't bail early.)
244 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed.
245 childFrame->loader().started();
247 FrameView* view = childFrame->view();
248 RenderObject* renderObject = renderer();
249 // We need to test the existence of renderObject and its widget-ness, as
250 // failing to do so causes problems.
251 if (renderObject && renderObject->isWidget() && view)
254 // Some loads are performed synchronously (e.g., about:blank and loads
255 // cancelled by returning a null ResourceRequest from requestFromDelegate).
256 // In these cases, the synchronous load would have finished
257 // before we could connect the signals, so make sure to send the
258 // completed() signal for the child by hand and mark the load as being
260 // FIXME: In this case the LocalFrame will have finished loading before
261 // it's being added to the child list. It would be a good idea to
262 // create the child first, then invoke the loader separately.
263 if (childFrame->loader().state() == FrameStateComplete && !childFrame->loader().policyDocumentLoader())
264 childFrame->loader().checkCompleted();
269 } // namespace WebCore