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 "CSSHelper.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 "ScriptEventListener.h"
38 #include "KURL.h"
39 #include "MappedAttribute.h"
40 #include "Page.h"
41 #include "RenderFrame.h"
42 #include "Settings.h"
43
44 namespace WebCore {
45
46 using namespace HTMLNames;
47
HTMLFrameElementBase(const QualifiedName & tagName,Document * document)48 HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* document)
49 : HTMLFrameOwnerElement(tagName, document)
50 , m_scrolling(ScrollbarAuto)
51 , m_marginWidth(-1)
52 , m_marginHeight(-1)
53 , m_noResize(false)
54 , m_viewSource(false)
55 , m_shouldOpenURLAfterAttach(false)
56 {
57 }
58
isURLAllowed(const AtomicString & URLString) const59 bool HTMLFrameElementBase::isURLAllowed(const AtomicString& URLString) const
60 {
61 if (URLString.isEmpty())
62 return true;
63
64 const KURL& completeURL = document()->completeURL(URLString);
65
66 // Don't allow more than 200 total frames in a set. This seems
67 // like a reasonable upper bound, and otherwise mutually recursive
68 // frameset pages can quickly bring the program to its knees with
69 // exponential growth in the number of frames.
70 // FIXME: This limit could be higher, but because WebKit has some
71 // algorithms that happen while loading which appear to be N^2 or
72 // worse in the number of frames, we'll keep it at 200 for now.
73 if (Frame* parentFrame = document()->frame()) {
74 if (parentFrame->page()->frameCount() > 200)
75 return false;
76 }
77
78 // We allow one level of self-reference because some sites depend on that.
79 // But we don't allow more than one.
80 bool foundSelfReference = false;
81 for (Frame* frame = document()->frame(); frame; frame = frame->tree()->parent()) {
82 if (equalIgnoringFragmentIdentifier(frame->loader()->url(), completeURL)) {
83 if (foundSelfReference)
84 return false;
85 foundSelfReference = true;
86 }
87 }
88
89 return true;
90 }
91
openURL()92 void HTMLFrameElementBase::openURL()
93 {
94 ASSERT(!m_frameName.isEmpty());
95
96 if (!isURLAllowed(m_URL))
97 return;
98
99 if (m_URL.isEmpty())
100 m_URL = blankURL().string();
101
102 Frame* parentFrame = document()->frame();
103 if (!parentFrame)
104 return;
105
106 parentFrame->loader()->requestFrame(this, m_URL, m_frameName);
107 if (contentFrame())
108 contentFrame()->setInViewSourceMode(viewSourceMode());
109 }
110
parseMappedAttribute(MappedAttribute * attr)111 void HTMLFrameElementBase::parseMappedAttribute(MappedAttribute *attr)
112 {
113 if (attr->name() == srcAttr)
114 setLocation(deprecatedParseURL(attr->value()));
115 else if (attr->name() == idAttr) {
116 // Important to call through to base for the id attribute so the hasID bit gets set.
117 HTMLFrameOwnerElement::parseMappedAttribute(attr);
118 m_frameName = attr->value();
119 } else if (attr->name() == nameAttr) {
120 m_frameName = attr->value();
121 // FIXME: If we are already attached, this doesn't actually change the frame's name.
122 // FIXME: If we are already attached, this doesn't check for frame name
123 // conflicts and generate a unique frame name.
124 } else if (attr->name() == marginwidthAttr) {
125 m_marginWidth = attr->value().toInt();
126 // FIXME: If we are already attached, this has no effect.
127 } else if (attr->name() == marginheightAttr) {
128 m_marginHeight = attr->value().toInt();
129 // FIXME: If we are already attached, this has no effect.
130 } else if (attr->name() == noresizeAttr) {
131 m_noResize = true;
132 // FIXME: If we are already attached, this has no effect.
133 } else if (attr->name() == scrollingAttr) {
134 // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling."
135 if (equalIgnoringCase(attr->value(), "auto") || equalIgnoringCase(attr->value(), "yes"))
136 m_scrolling = document()->frameElementsShouldIgnoreScrolling() ? ScrollbarAlwaysOff : ScrollbarAuto;
137 else if (equalIgnoringCase(attr->value(), "no"))
138 m_scrolling = ScrollbarAlwaysOff;
139 // FIXME: If we are already attached, this has no effect.
140 } else if (attr->name() == viewsourceAttr) {
141 m_viewSource = !attr->isNull();
142 if (contentFrame())
143 contentFrame()->setInViewSourceMode(viewSourceMode());
144 } else if (attr->name() == onloadAttr) {
145 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr));
146 } else if (attr->name() == onbeforeunloadAttr) {
147 // FIXME: should <frame> elements have beforeunload handlers?
148 setAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(this, attr));
149 } else
150 HTMLFrameOwnerElement::parseMappedAttribute(attr);
151 }
152
setNameAndOpenURL()153 void HTMLFrameElementBase::setNameAndOpenURL()
154 {
155 m_frameName = getAttribute(nameAttr);
156 if (m_frameName.isNull())
157 m_frameName = getAttribute(idAttr);
158
159 if (Frame* parentFrame = document()->frame())
160 m_frameName = parentFrame->tree()->uniqueChildName(m_frameName);
161
162 openURL();
163 }
164
setNameAndOpenURLCallback(Node * n)165 void HTMLFrameElementBase::setNameAndOpenURLCallback(Node* n)
166 {
167 static_cast<HTMLFrameElementBase*>(n)->setNameAndOpenURL();
168 }
169
insertedIntoDocument()170 void HTMLFrameElementBase::insertedIntoDocument()
171 {
172 HTMLFrameOwnerElement::insertedIntoDocument();
173
174 // We delay frame loading until after the render tree is fully constructed.
175 // Othewise, a synchronous load that executed JavaScript would see incorrect
176 // (0) values for the frame's renderer-dependent properties, like width.
177 m_shouldOpenURLAfterAttach = true;
178 }
179
removedFromDocument()180 void HTMLFrameElementBase::removedFromDocument()
181 {
182 m_shouldOpenURLAfterAttach = false;
183
184 HTMLFrameOwnerElement::removedFromDocument();
185 }
186
attach()187 void HTMLFrameElementBase::attach()
188 {
189 if (m_shouldOpenURLAfterAttach) {
190 m_shouldOpenURLAfterAttach = false;
191 queuePostAttachCallback(&HTMLFrameElementBase::setNameAndOpenURLCallback, this);
192 }
193
194 HTMLFrameOwnerElement::attach();
195
196 if (RenderPart* renderPart = toRenderPart(renderer())) {
197 if (Frame* frame = contentFrame())
198 renderPart->setWidget(frame->view());
199 }
200 }
201
location() const202 KURL HTMLFrameElementBase::location() const
203 {
204 return src();
205 }
206
setLocation(const String & str)207 void HTMLFrameElementBase::setLocation(const String& str)
208 {
209 Settings* settings = document()->settings();
210 if (settings && settings->needsAcrobatFrameReloadingQuirk() && m_URL == str)
211 return;
212
213 m_URL = AtomicString(str);
214
215 if (inDocument())
216 openURL();
217 }
218
isFocusable() const219 bool HTMLFrameElementBase::isFocusable() const
220 {
221 return renderer();
222 }
223
setFocus(bool received)224 void HTMLFrameElementBase::setFocus(bool received)
225 {
226 HTMLFrameOwnerElement::setFocus(received);
227 if (Page* page = document()->page())
228 page->focusController()->setFocusedFrame(received ? contentFrame() : 0);
229 }
230
isURLAttribute(Attribute * attr) const231 bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const
232 {
233 return attr->name() == srcAttr;
234 }
235
frameBorder() const236 String HTMLFrameElementBase::frameBorder() const
237 {
238 return getAttribute(frameborderAttr);
239 }
240
setFrameBorder(const String & value)241 void HTMLFrameElementBase::setFrameBorder(const String &value)
242 {
243 setAttribute(frameborderAttr, value);
244 }
245
longDesc() const246 String HTMLFrameElementBase::longDesc() const
247 {
248 return getAttribute(longdescAttr);
249 }
250
setLongDesc(const String & value)251 void HTMLFrameElementBase::setLongDesc(const String &value)
252 {
253 setAttribute(longdescAttr, value);
254 }
255
marginHeight() const256 String HTMLFrameElementBase::marginHeight() const
257 {
258 return getAttribute(marginheightAttr);
259 }
260
setMarginHeight(const String & value)261 void HTMLFrameElementBase::setMarginHeight(const String &value)
262 {
263 setAttribute(marginheightAttr, value);
264 }
265
marginWidth() const266 String HTMLFrameElementBase::marginWidth() const
267 {
268 return getAttribute(marginwidthAttr);
269 }
270
setMarginWidth(const String & value)271 void HTMLFrameElementBase::setMarginWidth(const String &value)
272 {
273 setAttribute(marginwidthAttr, value);
274 }
275
name() const276 String HTMLFrameElementBase::name() const
277 {
278 return getAttribute(nameAttr);
279 }
280
setName(const String & value)281 void HTMLFrameElementBase::setName(const String &value)
282 {
283 setAttribute(nameAttr, value);
284 }
285
setNoResize(bool noResize)286 void HTMLFrameElementBase::setNoResize(bool noResize)
287 {
288 setAttribute(noresizeAttr, noResize ? "" : 0);
289 }
290
scrolling() const291 String HTMLFrameElementBase::scrolling() const
292 {
293 return getAttribute(scrollingAttr);
294 }
295
setScrolling(const String & value)296 void HTMLFrameElementBase::setScrolling(const String &value)
297 {
298 setAttribute(scrollingAttr, value);
299 }
300
src() const301 KURL HTMLFrameElementBase::src() const
302 {
303 return document()->completeURL(getAttribute(srcAttr));
304 }
305
setSrc(const String & value)306 void HTMLFrameElementBase::setSrc(const String &value)
307 {
308 setAttribute(srcAttr, value);
309 }
310
width() const311 int HTMLFrameElementBase::width() const
312 {
313 if (!renderer())
314 return 0;
315
316 document()->updateLayoutIgnorePendingStylesheets();
317 return toRenderBox(renderer())->width();
318 }
319
height() const320 int HTMLFrameElementBase::height() const
321 {
322 if (!renderer())
323 return 0;
324
325 document()->updateLayoutIgnorePendingStylesheets();
326 return toRenderBox(renderer())->height();
327 }
328
329 } // namespace WebCore
330