1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Simon Hausmann (hausmann@kde.org)
5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "HTMLFrameElementBase.h"
26
27#include "Document.h"
28#include "FocusController.h"
29#include "Frame.h"
30#include "FrameLoader.h"
31#include "FrameView.h"
32#include "HTMLNames.h"
33#include "HTMLParserIdioms.h"
34#include "JSDOMBindingSecurity.h"
35#include "Page.h"
36#include "RenderWidget.h"
37#include "ScriptController.h"
38#include "Settings.h"
39#include "SubframeLoader.h"
40#include <wtf/IsoMallocInlines.h>
41#include <wtf/URL.h>
42
43namespace WebCore {
44
45WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLFrameElementBase);
46
47using namespace HTMLNames;
48
49HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document& document)
50 : HTMLFrameOwnerElement(tagName, document)
51 , m_scrolling(ScrollbarAuto)
52 , m_marginWidth(-1)
53 , m_marginHeight(-1)
54{
55 setHasCustomStyleResolveCallbacks();
56}
57
58bool HTMLFrameElementBase::isURLAllowed() const
59{
60 if (m_URL.isEmpty())
61 return true;
62
63 return isURLAllowed(document().completeURL(m_URL));
64}
65
66bool HTMLFrameElementBase::isURLAllowed(const URL& completeURL) const
67{
68 if (document().page() && document().page()->subframeCount() >= Page::maxNumberOfFrames)
69 return false;
70
71 if (completeURL.isEmpty())
72 return true;
73
74 if (WTF::protocolIsJavaScript(completeURL)) {
75 RefPtr<Document> contentDoc = this->contentDocument();
76 if (contentDoc && !ScriptController::canAccessFromCurrentOrigin(contentDoc->frame()))
77 return false;
78 }
79
80 RefPtr<Frame> parentFrame = document().frame();
81 if (parentFrame)
82 return parentFrame->isURLAllowed(completeURL);
83
84 return true;
85}
86
87void HTMLFrameElementBase::openURL(LockHistory lockHistory, LockBackForwardList lockBackForwardList)
88{
89 if (!isURLAllowed())
90 return;
91
92 if (m_URL.isEmpty())
93 m_URL = WTF::blankURL().string();
94
95 RefPtr<Frame> parentFrame = document().frame();
96 if (!parentFrame)
97 return;
98
99 String frameName = getNameAttribute();
100 if (frameName.isNull() && UNLIKELY(document().settings().needsFrameNameFallbackToIdQuirk()))
101 frameName = getIdAttribute();
102
103 parentFrame->loader().subframeLoader().requestFrame(*this, m_URL, frameName, lockHistory, lockBackForwardList);
104}
105
106void HTMLFrameElementBase::parseAttribute(const QualifiedName& name, const AtomicString& value)
107{
108 if (name == srcdocAttr)
109 setLocation("about:srcdoc");
110 else if (name == srcAttr && !hasAttributeWithoutSynchronization(srcdocAttr))
111 setLocation(stripLeadingAndTrailingHTMLSpaces(value));
112 else if (name == marginwidthAttr) {
113 m_marginWidth = value.toInt();
114 // FIXME: If we are already attached, this has no effect.
115 } else if (name == marginheightAttr) {
116 m_marginHeight = value.toInt();
117 // FIXME: If we are already attached, this has no effect.
118 } else if (name == scrollingAttr) {
119 // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling."
120 if (equalLettersIgnoringASCIICase(value, "auto") || equalLettersIgnoringASCIICase(value, "yes"))
121 m_scrolling = ScrollbarAuto;
122 else if (equalLettersIgnoringASCIICase(value, "no"))
123 m_scrolling = ScrollbarAlwaysOff;
124 // FIXME: If we are already attached, this has no effect.
125 } else
126 HTMLFrameOwnerElement::parseAttribute(name, value);
127}
128
129Node::InsertedIntoAncestorResult HTMLFrameElementBase::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
130{
131 HTMLFrameOwnerElement::insertedIntoAncestor(insertionType, parentOfInsertedTree);
132 if (insertionType.connectedToDocument)
133 return InsertedIntoAncestorResult::NeedsPostInsertionCallback;
134 return InsertedIntoAncestorResult::Done;
135}
136
137void HTMLFrameElementBase::didFinishInsertingNode()
138{
139 if (!isConnected())
140 return;
141
142 // DocumentFragments don't kick off any loads.
143 if (!document().frame())
144 return;
145
146 if (!SubframeLoadingDisabler::canLoadFrame(*this))
147 return;
148
149 if (!renderer())
150 invalidateStyleAndRenderersForSubtree();
151 openURL();
152}
153
154void HTMLFrameElementBase::didAttachRenderers()
155{
156 if (RenderWidget* part = renderWidget()) {
157 if (RefPtr<Frame> frame = contentFrame())
158 part->setWidget(frame->view());
159 }
160}
161
162URL HTMLFrameElementBase::location() const
163{
164 if (hasAttributeWithoutSynchronization(srcdocAttr))
165 return URL({ }, "about:srcdoc");
166 return document().completeURL(attributeWithoutSynchronization(srcAttr));
167}
168
169void HTMLFrameElementBase::setLocation(const String& str)
170{
171 if (document().settings().needsAcrobatFrameReloadingQuirk() && m_URL == str)
172 return;
173
174 m_URL = AtomicString(str);
175
176 if (isConnected())
177 openURL(LockHistory::No, LockBackForwardList::No);
178}
179
180void HTMLFrameElementBase::setLocation(JSC::ExecState& state, const String& newLocation)
181{
182 if (WTF::protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(newLocation))) {
183 if (!BindingSecurity::shouldAllowAccessToNode(state, contentDocument()))
184 return;
185 }
186
187 setLocation(newLocation);
188}
189
190bool HTMLFrameElementBase::supportsFocus() const
191{
192 return true;
193}
194
195void HTMLFrameElementBase::setFocus(bool received)
196{
197 HTMLFrameOwnerElement::setFocus(received);
198 if (Page* page = document().page()) {
199 if (received)
200 page->focusController().setFocusedFrame(contentFrame());
201 else if (page->focusController().focusedFrame() == contentFrame()) // Focus may have already been given to another frame, don't take it away.
202 page->focusController().setFocusedFrame(0);
203 }
204}
205
206bool HTMLFrameElementBase::isURLAttribute(const Attribute& attribute) const
207{
208 return attribute.name() == srcAttr || attribute.name() == longdescAttr || HTMLFrameOwnerElement::isURLAttribute(attribute);
209}
210
211bool HTMLFrameElementBase::isHTMLContentAttribute(const Attribute& attribute) const
212{
213 return attribute.name() == srcdocAttr || HTMLFrameOwnerElement::isHTMLContentAttribute(attribute);
214}
215
216int HTMLFrameElementBase::width()
217{
218 document().updateLayoutIgnorePendingStylesheets();
219 if (!renderBox())
220 return 0;
221 return renderBox()->width();
222}
223
224int HTMLFrameElementBase::height()
225{
226 document().updateLayoutIgnorePendingStylesheets();
227 if (!renderBox())
228 return 0;
229 return renderBox()->height();
230}
231
232} // namespace WebCore
233