210feed1d9f7cce06d7570b160e4b11017678473
[WebKit-https.git] / WebCore / html / HTMLFrameElement.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Simon Hausmann (hausmann@kde.org)
7  *           (C) 2001 Dirk Mueller (mueller@kde.org)
8  * Copyright (C) 2004, 2006 Apple Computer, Inc.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25 #include "config.h"
26 #include "HTMLFrameElement.h"
27
28 #include "csshelper.h"
29 #include "Document.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "FrameTree.h"
33 #include "FrameView.h"
34 #include "HTMLNames.h"
35 #include "HTMLFrameSetElement.h"
36 #include "Page.h"
37 #include "RenderFrame.h"
38
39 namespace WebCore {
40
41 using namespace EventNames;
42 using namespace HTMLNames;
43
44 HTMLFrameElement::HTMLFrameElement(Document *doc)
45     : HTMLElement(frameTag, doc)
46 {
47     init();
48 }
49
50 HTMLFrameElement::HTMLFrameElement(const QualifiedName& tagName, Document *doc)
51     : HTMLElement(tagName, doc)
52 {
53     init();
54 }
55
56 void HTMLFrameElement::init()
57 {
58     m_frameBorder = true;
59     m_frameBorderSet = false;
60     m_marginWidth = -1;
61     m_marginHeight = -1;
62     m_scrolling = ScrollBarAuto;
63     m_noResize = false;
64     m_viewSource = false;
65 }
66
67 HTMLFrameElement::~HTMLFrameElement()
68 {
69 }
70
71 bool HTMLFrameElement::isURLAllowed(const AtomicString &URLString) const
72 {
73     if (URLString.isEmpty())
74         return true;
75     
76     FrameView* w = document()->view();
77     if (!w)
78         return false;
79
80     KURL newURL(document()->completeURL(URLString.deprecatedString()));
81     newURL.setRef(DeprecatedString::null);
82
83     // Don't allow more than 200 total frames in a set. This seems
84     // like a reasonable upper bound, and otherwise mutually recursive
85     // frameset pages can quickly bring the program to its knees with
86     // exponential growth in the number of frames.
87
88     // FIXME: This limit could be higher, but WebKit has some
89     // algorithms that happen while loading which appear to be N^2 or
90     // worse in the number of frames
91     if (w->frame()->page()->frameCount() > 200)
92         return false;
93
94     // We allow one level of self-reference because some sites depend on that.
95     // But we don't allow more than one.
96     bool foundSelfReference = false;
97     for (Frame *frame = w->frame(); frame; frame = frame->tree()->parent()) {
98         KURL frameURL = frame->url();
99         frameURL.setRef(DeprecatedString::null);
100         if (frameURL == newURL) {
101             if (foundSelfReference)
102                 return false;
103             foundSelfReference = true;
104         }
105     }
106     
107     return true;
108 }
109
110 void HTMLFrameElement::openURL()
111 {
112     if (!isURLAllowed(m_URL))
113         return;
114
115     if (m_URL.isEmpty())
116         m_URL = "about:blank";
117
118     document()->frame()->requestFrame(this, m_URL, m_name);
119
120     // FIXME: This is a relic from how HTMLIFrameElement used to do things.
121     // It's probably unnecessary, since viewsource mode doesn't really work,
122     // and both parseMappedAttribute and attach include the same check.
123     if (contentFrame())
124         contentFrame()->setInViewSourceMode(viewSourceMode());
125 }
126
127 void HTMLFrameElement::parseMappedAttribute(MappedAttribute *attr)
128 {
129     if (attr->name() == srcAttr)
130         setLocation(parseURL(attr->value()));
131     else if (attr->name() == idAttr) {
132         // Important to call through to base for the id attribute so the hasID bit gets set.
133         HTMLElement::parseMappedAttribute(attr);
134         m_name = attr->value();
135     } else if (attr->name() == nameAttr) {
136         m_name = attr->value();
137         // FIXME: If we are already attached, this doesn't actually change the frame's name.
138         // FIXME: If we are already attached, this doesn't check for frame name
139         // conflicts and generate a unique frame name.
140     } else if (attr->name() == frameborderAttr) {
141         m_frameBorder = attr->value().toInt();
142         m_frameBorderSet = !attr->isNull();
143         // FIXME: If we are already attached, this has no effect.
144     } else if (attr->name() == marginwidthAttr) {
145         m_marginWidth = attr->value().toInt();
146         // FIXME: If we are already attached, this has no effect.
147     } else if (attr->name() == marginheightAttr) {
148         m_marginHeight = attr->value().toInt();
149         // FIXME: If we are already attached, this has no effect.
150     } else if (attr->name() == noresizeAttr) {
151         m_noResize = true;
152         // FIXME: If we are already attached, this has no effect.
153     } else if (attr->name() == scrollingAttr) {
154         // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling."
155         if (equalIgnoringCase(attr->value(), "auto") || equalIgnoringCase(attr->value(), "yes"))
156             m_scrolling = ScrollBarAuto;
157         else if (equalIgnoringCase(attr->value(), "no"))
158             m_scrolling = ScrollBarAlwaysOff;
159         // FIXME: If we are already attached, this has no effect.
160     } else if (attr->name() == viewsourceAttr) {
161         m_viewSource = !attr->isNull();
162         if (contentFrame())
163             contentFrame()->setInViewSourceMode(viewSourceMode());
164     } else if (attr->name() == onloadAttr) {
165         setHTMLEventListener(loadEvent, attr);
166     } else if (attr->name() == onbeforeunloadAttr) {
167         // FIXME: should <frame> elements have beforeunload handlers?
168         setHTMLEventListener(beforeunloadEvent, attr);
169     } else if (attr->name() == onunloadAttr) {
170         setHTMLEventListener(unloadEvent, attr);
171     } else
172         HTMLElement::parseMappedAttribute(attr);
173 }
174
175 bool HTMLFrameElement::rendererIsNeeded(RenderStyle *style)
176 {
177     // Ignore display: none.
178     return isURLAllowed(m_URL);
179 }
180
181 RenderObject *HTMLFrameElement::createRenderer(RenderArena *arena, RenderStyle *style)
182 {
183     return new (arena) RenderFrame(this);
184 }
185
186 void HTMLFrameElement::attach()
187 {
188     m_name = getAttribute(nameAttr);
189     if (m_name.isNull())
190         m_name = getAttribute(idAttr);
191
192     // inherit default settings from parent frameset
193     for (Node *node = parentNode(); node; node = node->parentNode())
194         if (node->hasTagName(framesetTag)) {
195             HTMLFrameSetElement* frameset = static_cast<HTMLFrameSetElement*>(node);
196             if (!m_frameBorderSet)
197                 m_frameBorder = frameset->frameBorder();
198             if (!m_noResize)
199                 m_noResize = frameset->noResize();
200             break;
201         }
202
203     HTMLElement::attach();
204
205     if (!renderer())
206         return;
207
208     Frame* frame = document()->frame();
209
210     if (!frame)
211         return;
212
213     AtomicString relativeURL = m_URL;
214     if (relativeURL.isEmpty())
215         relativeURL = "about:blank";
216
217     m_name = frame->tree()->uniqueChildName(m_name);
218
219     // load the frame contents
220     frame->requestFrame(this, relativeURL, m_name);
221     
222     if (contentFrame())
223         contentFrame()->setInViewSourceMode(viewSourceMode());
224 }
225
226 void HTMLFrameElement::close()
227 {
228     Frame* frame = contentFrame();
229     if (frame && renderer()) {
230         frame->frameDetached();
231         frame->disconnectOwnerElement();
232     }
233 }
234
235 void HTMLFrameElement::willRemove()
236 {
237     // close the frame and dissociate the renderer, but leave the
238     // node attached so that frame does not get re-attached before
239     // actually leaving the document.  see <rdar://problem/4132581>
240     close();
241     if (renderer()) {
242         renderer()->destroy();
243         setRenderer(0);
244     }
245     
246     HTMLElement::willRemove();
247 }
248
249 void HTMLFrameElement::detach()
250 {
251     close();
252     HTMLElement::detach();
253 }
254
255 void HTMLFrameElement::setLocation(const String& str)
256 {
257     m_URL = AtomicString(str);
258
259     if (!attached()) {
260         return;
261     }
262     
263     // Handle the common case where we decided not to make a frame the first time.
264     // Detach and the let attach() decide again whether to make the frame for this URL.
265     if (!renderer() && !hasTagName(iframeTag)) {
266         detach();
267         attach();
268         return;
269     }
270     
271     openURL();
272 }
273
274 bool HTMLFrameElement::isFocusable() const
275 {
276     return renderer();
277 }
278
279 void HTMLFrameElement::setFocus(bool received)
280 {
281     HTMLElement::setFocus(received);
282     RenderFrame *renderFrame = static_cast<RenderFrame *>(renderer());
283     if (!renderFrame || !renderFrame->widget())
284         return;
285     if (received)
286         renderFrame->widget()->setFocus();
287     else
288         renderFrame->widget()->clearFocus();
289 }
290
291 Frame* HTMLFrameElement::contentFrame() const
292 {
293     // Start with the part that contains this element, our ownerDocument.
294     Frame* parentFrame = document()->frame();
295     if (!parentFrame)
296         return 0;
297
298     // Find the part for the subframe that this element represents.
299     return parentFrame->tree()->child(m_name);
300 }
301
302 Document* HTMLFrameElement::contentDocument() const
303 {
304     Frame* frame = contentFrame();
305     if (!frame)
306         return 0;
307     return frame->document();
308 }
309
310 bool HTMLFrameElement::isURLAttribute(Attribute *attr) const
311 {
312     return attr->name() == srcAttr;
313 }
314
315 String HTMLFrameElement::frameBorder() const
316 {
317     return getAttribute(frameborderAttr);
318 }
319
320 void HTMLFrameElement::setFrameBorder(const String &value)
321 {
322     setAttribute(frameborderAttr, value);
323 }
324
325 String HTMLFrameElement::longDesc() const
326 {
327     return getAttribute(longdescAttr);
328 }
329
330 void HTMLFrameElement::setLongDesc(const String &value)
331 {
332     setAttribute(longdescAttr, value);
333 }
334
335 String HTMLFrameElement::marginHeight() const
336 {
337     return getAttribute(marginheightAttr);
338 }
339
340 void HTMLFrameElement::setMarginHeight(const String &value)
341 {
342     setAttribute(marginheightAttr, value);
343 }
344
345 String HTMLFrameElement::marginWidth() const
346 {
347     return getAttribute(marginwidthAttr);
348 }
349
350 void HTMLFrameElement::setMarginWidth(const String &value)
351 {
352     setAttribute(marginwidthAttr, value);
353 }
354
355 String HTMLFrameElement::name() const
356 {
357     return getAttribute(nameAttr);
358 }
359
360 void HTMLFrameElement::setName(const String &value)
361 {
362     setAttribute(nameAttr, value);
363 }
364
365 void HTMLFrameElement::setNoResize(bool noResize)
366 {
367     setAttribute(noresizeAttr, noResize ? "" : 0);
368 }
369
370 String HTMLFrameElement::scrolling() const
371 {
372     return getAttribute(scrollingAttr);
373 }
374
375 void HTMLFrameElement::setScrolling(const String &value)
376 {
377     setAttribute(scrollingAttr, value);
378 }
379
380 String HTMLFrameElement::src() const
381 {
382     return document()->completeURL(getAttribute(srcAttr));
383 }
384
385 void HTMLFrameElement::setSrc(const String &value)
386 {
387     setAttribute(srcAttr, value);
388 }
389
390 int HTMLFrameElement::frameWidth() const
391 {
392     if (!renderer())
393         return 0;
394     
395     document()->updateLayoutIgnorePendingStylesheets();
396     return renderer()->width();
397 }
398
399 int HTMLFrameElement::frameHeight() const
400 {
401     if (!renderer())
402         return 0;
403     
404     document()->updateLayoutIgnorePendingStylesheets();
405     return renderer()->height();
406 }
407
408 }