Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / HTMLFrameOwnerElement.cpp
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/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"
37
38 namespace WebCore {
39
40 typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap;
41 static WidgetToParentMap& widgetNewParentMap()
42 {
43     DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ());
44     return map;
45 }
46
47 static unsigned s_updateSuspendCount = 0;
48
49 HTMLFrameOwnerElement::UpdateSuspendScope::UpdateSuspendScope()
50 {
51     ++s_updateSuspendCount;
52 }
53
54 void HTMLFrameOwnerElement::UpdateSuspendScope::performDeferredWidgetTreeOperations()
55 {
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) {
64             if (currentParent)
65                 currentParent->removeChild(child);
66             if (newParent)
67                 newParent->addChild(child);
68         }
69     }
70 }
71
72 HTMLFrameOwnerElement::UpdateSuspendScope::~UpdateSuspendScope()
73 {
74     ASSERT(s_updateSuspendCount > 0);
75     if (s_updateSuspendCount == 1)
76         performDeferredWidgetTreeOperations();
77     --s_updateSuspendCount;
78 }
79
80 static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
81 {
82     if (!s_updateSuspendCount) {
83         if (parent)
84             parent->addChild(child);
85         else if (toScrollView(child->parent()))
86             toScrollView(child->parent())->removeChild(child);
87         return;
88     }
89     widgetNewParentMap().set(child, parent);
90 }
91
92 HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document& document)
93     : HTMLElement(tagName, document)
94     , m_contentFrame(0)
95     , m_widget(nullptr)
96     , m_sandboxFlags(SandboxNone)
97 {
98 }
99
100 RenderPart* HTMLFrameOwnerElement::renderPart() const
101 {
102     // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
103     // when using fallback content.
104     if (!renderer() || !renderer()->isRenderPart())
105         return 0;
106     return toRenderPart(renderer());
107 }
108
109 void HTMLFrameOwnerElement::setContentFrame(Frame& frame)
110 {
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;
116
117     for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
118         node->incrementConnectedSubframeCount();
119 }
120
121 void HTMLFrameOwnerElement::clearContentFrame()
122 {
123     if (!m_contentFrame)
124         return;
125
126     m_contentFrame = 0;
127
128     for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
129         node->decrementConnectedSubframeCount();
130 }
131
132 void HTMLFrameOwnerElement::disconnectContentFrame()
133 {
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();
143     }
144 }
145
146 HTMLFrameOwnerElement::~HTMLFrameOwnerElement()
147 {
148     if (m_contentFrame)
149         m_contentFrame->disconnectOwnerElement();
150 }
151
152 Document* HTMLFrameOwnerElement::contentDocument() const
153 {
154     return (m_contentFrame && m_contentFrame->isLocalFrame()) ? toLocalFrame(m_contentFrame)->document() : 0;
155 }
156
157 DOMWindow* HTMLFrameOwnerElement::contentWindow() const
158 {
159     return m_contentFrame ? m_contentFrame->domWindow() : 0;
160 }
161
162 void HTMLFrameOwnerElement::setSandboxFlags(SandboxFlags flags)
163 {
164     m_sandboxFlags = flags;
165 }
166
167 bool HTMLFrameOwnerElement::isKeyboardFocusable() const
168 {
169     return m_contentFrame && HTMLElement::isKeyboardFocusable();
170 }
171
172 Document* HTMLFrameOwnerElement::getSVGDocument(ExceptionState& exceptionState) const
173 {
174     Document* doc = contentDocument();
175     if (doc && doc->isSVGDocument())
176         return doc;
177     return 0;
178 }
179
180 void HTMLFrameOwnerElement::setWidget(PassRefPtr<Widget> widget)
181 {
182     if (widget == m_widget)
183         return;
184
185     if (m_widget) {
186         if (m_widget->parent())
187             moveWidgetToParentSoon(m_widget.get(), 0);
188         m_widget = nullptr;
189     }
190
191     m_widget = widget;
192
193     RenderWidget* renderWidget = toRenderWidget(renderer());
194     if (!renderWidget)
195         return;
196
197     if (m_widget) {
198         renderWidget->updateOnWidgetChange();
199
200         ASSERT(document().view() == renderWidget->frameView());
201         ASSERT(renderWidget->frameView());
202         moveWidgetToParentSoon(m_widget.get(), renderWidget->frameView());
203     }
204
205     if (AXObjectCache* cache = document().existingAXObjectCache())
206         cache->childrenChanged(renderWidget);
207 }
208
209 Widget* HTMLFrameOwnerElement::ownedWidget() const
210 {
211     return m_widget.get();
212 }
213
214 bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const AtomicString& frameName, bool lockBackForwardList)
215 {
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);
220         return true;
221     }
222
223     if (!document().securityOrigin()->canDisplay(url)) {
224         FrameLoader::reportLocalLoadFailed(parentFrame.get(), url.string());
225         return false;
226     }
227
228     if (!SubframeLoadingDisabler::canLoadFrame(*this))
229         return false;
230
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);
233
234     if (!childFrame)  {
235         parentFrame->loader().checkCompleted();
236         return false;
237     }
238
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();
246
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)
252         setWidget(view);
253
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
259     // complete.
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();
265     return true;
266 }
267
268
269 } // namespace WebCore