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, 2006, 2008, 2009 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 "Attribute.h"
28 #include "Document.h"
29 #include "EventNames.h"
30 #include "FocusController.h"
31 #include "Frame.h"
32 #include "FrameLoader.h"
33 #include "FrameTree.h"
34 #include "FrameView.h"
35 #include "HTMLFrameSetElement.h"
36 #include "HTMLNames.h"
37 #include "HTMLParserIdioms.h"
38 #include "KURL.h"
39 #include "Page.h"
40 #include "RenderEmbeddedObject.h"
41 #include "RenderFrame.h"
42 #include "ScriptController.h"
43 #include "ScriptEventListener.h"
44 #include "Settings.h"
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
HTMLFrameElementBase(const QualifiedName & tagName,Document * document)50 HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* document)
51 : HTMLFrameOwnerElement(tagName, document)
52 , m_scrolling(ScrollbarAuto)
53 , m_marginWidth(-1)
54 , m_marginHeight(-1)
55 , m_checkInDocumentTimer(this, &HTMLFrameElementBase::checkInDocumentTimerFired)
56 , m_viewSource(false)
57 , m_remainsAliveOnRemovalFromTree(false)
58 {
59 }
60
isURLAllowed() const61 bool HTMLFrameElementBase::isURLAllowed() const
62 {
63 if (m_URL.isEmpty())
64 return true;
65
66 const KURL& completeURL = document()->completeURL(m_URL);
67
68 if (protocolIsJavaScript(completeURL)) {
69 Document* contentDoc = this->contentDocument();
70 if (contentDoc && !ScriptController::canAccessFromCurrentOrigin(contentDoc->frame()))
71 return false;
72 }
73
74 if (Frame* parentFrame = document()->frame()) {
75 if (parentFrame->page()->frameCount() >= Page::maxNumberOfFrames)
76 return false;
77 }
78
79 // We allow one level of self-reference because some sites depend on that.
80 // But we don't allow more than one.
81 bool foundSelfReference = false;
82 for (Frame* frame = document()->frame(); frame; frame = frame->tree()->parent()) {
83 if (equalIgnoringFragmentIdentifier(frame->document()->url(), completeURL)) {
84 if (foundSelfReference)
85 return false;
86 foundSelfReference = true;
87 }
88 }
89
90 return true;
91 }
92
openURL(bool lockHistory,bool lockBackForwardList)93 void HTMLFrameElementBase::openURL(bool lockHistory, bool lockBackForwardList)
94 {
95 if (!isURLAllowed())
96 return;
97
98 if (m_URL.isEmpty())
99 m_URL = blankURL().string();
100
101 Frame* parentFrame = document()->frame();
102 if (!parentFrame)
103 return;
104
105 parentFrame->loader()->subframeLoader()->requestFrame(this, m_URL, m_frameName, lockHistory, lockBackForwardList);
106 if (contentFrame())
107 contentFrame()->setInViewSourceMode(viewSourceMode());
108 }
109
parseMappedAttribute(Attribute * attr)110 void HTMLFrameElementBase::parseMappedAttribute(Attribute* attr)
111 {
112 if (attr->name() == srcAttr)
113 setLocation(stripLeadingAndTrailingHTMLSpaces(attr->value()));
114 else if (isIdAttributeName(attr->name())) {
115 // Important to call through to base for the id attribute so the hasID bit gets set.
116 HTMLFrameOwnerElement::parseMappedAttribute(attr);
117 m_frameName = attr->value();
118 } else if (attr->name() == nameAttr) {
119 m_frameName = attr->value();
120 // FIXME: If we are already attached, this doesn't actually change the frame's name.
121 // FIXME: If we are already attached, this doesn't check for frame name
122 // conflicts and generate a unique frame name.
123 } else if (attr->name() == marginwidthAttr) {
124 m_marginWidth = attr->value().toInt();
125 // FIXME: If we are already attached, this has no effect.
126 } else if (attr->name() == marginheightAttr) {
127 m_marginHeight = attr->value().toInt();
128 // FIXME: If we are already attached, this has no effect.
129 } else if (attr->name() == scrollingAttr) {
130 // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling."
131 if (equalIgnoringCase(attr->value(), "auto") || equalIgnoringCase(attr->value(), "yes"))
132 m_scrolling = document()->frameElementsShouldIgnoreScrolling() ? ScrollbarAlwaysOff : ScrollbarAuto;
133 else if (equalIgnoringCase(attr->value(), "no"))
134 m_scrolling = ScrollbarAlwaysOff;
135 // FIXME: If we are already attached, this has no effect.
136 } else if (attr->name() == viewsourceAttr) {
137 m_viewSource = !attr->isNull();
138 if (contentFrame())
139 contentFrame()->setInViewSourceMode(viewSourceMode());
140 } else if (attr->name() == onloadAttr)
141 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
142 else if (attr->name() == onbeforeloadAttr)
143 setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr));
144 else if (attr->name() == onbeforeunloadAttr) {
145 // FIXME: should <frame> elements have beforeunload handlers?
146 setAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(this, attr));
147 } else
148 HTMLFrameOwnerElement::parseMappedAttribute(attr);
149 }
150
setNameAndOpenURL()151 void HTMLFrameElementBase::setNameAndOpenURL()
152 {
153 m_frameName = getAttribute(nameAttr);
154 if (m_frameName.isNull())
155 m_frameName = getIdAttribute();
156 openURL();
157 }
158
updateOnReparenting()159 void HTMLFrameElementBase::updateOnReparenting()
160 {
161 ASSERT(m_remainsAliveOnRemovalFromTree);
162
163 if (Frame* frame = contentFrame())
164 frame->transferChildFrameToNewDocument();
165 }
166
insertedIntoDocument()167 void HTMLFrameElementBase::insertedIntoDocument()
168 {
169 HTMLFrameOwnerElement::insertedIntoDocument();
170
171 if (m_remainsAliveOnRemovalFromTree) {
172 updateOnReparenting();
173 setRemainsAliveOnRemovalFromTree(false);
174 return;
175 }
176 // DocumentFragments don't kick of any loads.
177 if (!document()->frame())
178 return;
179
180 // Loads may cause synchronous javascript execution (e.g. beforeload or
181 // src=javascript), which could try to access the renderer before the normal
182 // parser machinery would call lazyAttach() and set us as needing style
183 // resolve. Any code which expects this to be attached will resolve style
184 // before using renderer(), so this will make sure we attach in time.
185 // FIXME: Normally lazyAttach marks the renderer as attached(), but we don't
186 // want to do that here, as as callers expect to call attach() right after
187 // this and attach() will ASSERT(!attached())
188 ASSERT(!renderer()); // This recalc is unecessary if we already have a renderer.
189 lazyAttach(DoNotSetAttached);
190 setNameAndOpenURL();
191 }
192
attach()193 void HTMLFrameElementBase::attach()
194 {
195 HTMLFrameOwnerElement::attach();
196
197 if (RenderPart* part = renderPart()) {
198 if (Frame* frame = contentFrame())
199 part->setWidget(frame->view());
200 }
201 }
202
location() const203 KURL HTMLFrameElementBase::location() const
204 {
205 return document()->completeURL(getAttribute(srcAttr));
206 }
207
setLocation(const String & str)208 void HTMLFrameElementBase::setLocation(const String& str)
209 {
210 Settings* settings = document()->settings();
211 if (settings && settings->needsAcrobatFrameReloadingQuirk() && m_URL == str)
212 return;
213
214 m_URL = AtomicString(str);
215
216 if (inDocument())
217 openURL(false, false);
218 }
219
supportsFocus() const220 bool HTMLFrameElementBase::supportsFocus() const
221 {
222 return true;
223 }
224
setFocus(bool received)225 void HTMLFrameElementBase::setFocus(bool received)
226 {
227 HTMLFrameOwnerElement::setFocus(received);
228 if (Page* page = document()->page()) {
229 if (received)
230 page->focusController()->setFocusedFrame(contentFrame());
231 else if (page->focusController()->focusedFrame() == contentFrame()) // Focus may have already been given to another frame, don't take it away.
232 page->focusController()->setFocusedFrame(0);
233 }
234 }
235
isURLAttribute(Attribute * attr) const236 bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const
237 {
238 return attr->name() == srcAttr;
239 }
240
width() const241 int HTMLFrameElementBase::width() const
242 {
243 document()->updateLayoutIgnorePendingStylesheets();
244 if (!renderBox())
245 return 0;
246 return renderBox()->width();
247 }
248
height() const249 int HTMLFrameElementBase::height() const
250 {
251 document()->updateLayoutIgnorePendingStylesheets();
252 if (!renderBox())
253 return 0;
254 return renderBox()->height();
255 }
256
setRemainsAliveOnRemovalFromTree(bool value)257 void HTMLFrameElementBase::setRemainsAliveOnRemovalFromTree(bool value)
258 {
259 m_remainsAliveOnRemovalFromTree = value;
260
261 // There is a possibility that JS will do document.adoptNode() on this element but will not insert it into the tree.
262 // Start the async timer that is normally stopped by attach(). If it's not stopped and fires, it'll unload the frame.
263 if (value)
264 m_checkInDocumentTimer.startOneShot(0);
265 else
266 m_checkInDocumentTimer.stop();
267 }
268
checkInDocumentTimerFired(Timer<HTMLFrameElementBase> *)269 void HTMLFrameElementBase::checkInDocumentTimerFired(Timer<HTMLFrameElementBase>*)
270 {
271 ASSERT(!attached());
272 ASSERT(m_remainsAliveOnRemovalFromTree);
273
274 m_remainsAliveOnRemovalFromTree = false;
275 willRemove();
276 }
277
willRemove()278 void HTMLFrameElementBase::willRemove()
279 {
280 if (m_remainsAliveOnRemovalFromTree)
281 return;
282
283 HTMLFrameOwnerElement::willRemove();
284 }
285
286 #if ENABLE(FULLSCREEN_API)
allowFullScreen() const287 bool HTMLFrameElementBase::allowFullScreen() const
288 {
289 return hasAttribute(webkitallowfullscreenAttr);
290 }
291 #endif
292
293 } // namespace WebCore
294