LayoutTests:
[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     if (contentFrame())
121         contentFrame()->setInViewSourceMode(viewSourceMode());
122 }
123
124 void HTMLFrameElement::parseMappedAttribute(MappedAttribute *attr)
125 {
126     if (attr->name() == srcAttr)
127         setLocation(parseURL(attr->value()));
128     else if (attr->name() == idAttr) {
129         // Important to call through to base for the id attribute so the hasID bit gets set.
130         HTMLElement::parseMappedAttribute(attr);
131         m_name = attr->value();
132     } else if (attr->name() == nameAttr) {
133         m_name = attr->value();
134         // FIXME: If we are already attached, this doesn't actually change the frame's name.
135         // FIXME: If we are already attached, this doesn't check for frame name
136         // conflicts and generate a unique frame name.
137     } else if (attr->name() == frameborderAttr) {
138         m_frameBorder = attr->value().toInt();
139         m_frameBorderSet = !attr->isNull();
140         // FIXME: If we are already attached, this has no effect.
141     } else if (attr->name() == marginwidthAttr) {
142         m_marginWidth = attr->value().toInt();
143         // FIXME: If we are already attached, this has no effect.
144     } else if (attr->name() == marginheightAttr) {
145         m_marginHeight = attr->value().toInt();
146         // FIXME: If we are already attached, this has no effect.
147     } else if (attr->name() == noresizeAttr) {
148         m_noResize = true;
149         // FIXME: If we are already attached, this has no effect.
150     } else if (attr->name() == scrollingAttr) {
151         // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling."
152         if (equalIgnoringCase(attr->value(), "auto") || equalIgnoringCase(attr->value(), "yes"))
153             m_scrolling = ScrollBarAuto;
154         else if (equalIgnoringCase(attr->value(), "no"))
155             m_scrolling = ScrollBarAlwaysOff;
156         // FIXME: If we are already attached, this has no effect.
157     } else if (attr->name() == viewsourceAttr) {
158         m_viewSource = !attr->isNull();
159         if (contentFrame())
160             contentFrame()->setInViewSourceMode(viewSourceMode());
161     } else if (attr->name() == onloadAttr) {
162         setHTMLEventListener(loadEvent, attr);
163     } else if (attr->name() == onbeforeunloadAttr) {
164         // FIXME: should <frame> elements have beforeunload handlers?
165         setHTMLEventListener(beforeunloadEvent, attr);
166     } else if (attr->name() == onunloadAttr) {
167         setHTMLEventListener(unloadEvent, attr);
168     } else
169         HTMLElement::parseMappedAttribute(attr);
170 }
171
172 bool HTMLFrameElement::rendererIsNeeded(RenderStyle *style)
173 {
174     // Ignore display: none.
175     return isURLAllowed(m_URL);
176 }
177
178 RenderObject *HTMLFrameElement::createRenderer(RenderArena *arena, RenderStyle *style)
179 {
180     return new (arena) RenderFrame(this);
181 }
182
183 void HTMLFrameElement::insertedIntoDocument()
184 {
185     HTMLElement::insertedIntoDocument();
186     
187     m_name = getAttribute(nameAttr);
188     if (m_name.isNull())
189         m_name = getAttribute(idAttr);
190
191     if (Frame* parentFrame = document()->frame())
192         m_name = parentFrame->tree()->uniqueChildName(m_name);
193 }
194
195 void HTMLFrameElement::attach()
196 {
197     HTMLElement::attach();
198     
199     if (hasTagName(frameTag)) {
200         if (HTMLFrameSetElement* frameSetElement = containingFrameSetElement()) {
201             if (!m_frameBorderSet)
202                 m_frameBorder = frameSetElement->frameBorder();
203             if (!m_noResize)
204                 m_noResize = frameSetElement->noResize();
205         }
206     }
207         
208     if (!contentFrame())
209         openURL();
210 }
211
212 void HTMLFrameElement::close()
213 {
214     Frame* frame = contentFrame();
215     if (frame && renderer()) {
216         frame->frameDetached();
217         frame->disconnectOwnerElement();
218     }
219 }
220
221 void HTMLFrameElement::willRemove()
222 {
223     // close the frame and dissociate the renderer, but leave the
224     // node attached so that frame does not get re-attached before
225     // actually leaving the document.  see <rdar://problem/4132581>
226     close();
227     if (renderer()) {
228         renderer()->destroy();
229         setRenderer(0);
230     }
231     
232     HTMLElement::willRemove();
233 }
234
235 void HTMLFrameElement::detach()
236 {
237     close();
238     HTMLElement::detach();
239 }
240
241 void HTMLFrameElement::setLocation(const String& str)
242 {
243     m_URL = AtomicString(str);
244
245     if (!attached()) {
246         return;
247     }
248     
249     // Handle the common case where we decided not to make a frame the first time.
250     // Detach and the let attach() decide again whether to make the frame for this URL.
251     if (!renderer() && !hasTagName(iframeTag)) {
252         detach();
253         attach();
254         return;
255     }
256     
257     openURL();
258 }
259
260 bool HTMLFrameElement::isFocusable() const
261 {
262     return renderer();
263 }
264
265 void HTMLFrameElement::setFocus(bool received)
266 {
267     HTMLElement::setFocus(received);
268     RenderFrame *renderFrame = static_cast<RenderFrame *>(renderer());
269     if (!renderFrame || !renderFrame->widget())
270         return;
271     if (received)
272         renderFrame->widget()->setFocus();
273     else
274         renderFrame->widget()->clearFocus();
275 }
276
277 Frame* HTMLFrameElement::contentFrame() const
278 {
279     // Start with the part that contains this element, our ownerDocument.
280     Frame* parentFrame = document()->frame();
281     if (!parentFrame)
282         return 0;
283
284     // Find the part for the subframe that this element represents.
285     return parentFrame->tree()->child(m_name);
286 }
287
288 Document* HTMLFrameElement::contentDocument() const
289 {
290     Frame* frame = contentFrame();
291     if (!frame)
292         return 0;
293     return frame->document();
294 }
295
296 HTMLFrameSetElement* HTMLFrameElement::containingFrameSetElement() const
297 {
298     for (Node* node = parentNode(); node; node = node->parentNode())
299         if (node->hasTagName(framesetTag))
300             return static_cast<HTMLFrameSetElement*>(node);
301
302     return 0;
303 }
304
305 bool HTMLFrameElement::isURLAttribute(Attribute *attr) const
306 {
307     return attr->name() == srcAttr;
308 }
309
310 String HTMLFrameElement::frameBorder() const
311 {
312     return getAttribute(frameborderAttr);
313 }
314
315 void HTMLFrameElement::setFrameBorder(const String &value)
316 {
317     setAttribute(frameborderAttr, value);
318 }
319
320 String HTMLFrameElement::longDesc() const
321 {
322     return getAttribute(longdescAttr);
323 }
324
325 void HTMLFrameElement::setLongDesc(const String &value)
326 {
327     setAttribute(longdescAttr, value);
328 }
329
330 String HTMLFrameElement::marginHeight() const
331 {
332     return getAttribute(marginheightAttr);
333 }
334
335 void HTMLFrameElement::setMarginHeight(const String &value)
336 {
337     setAttribute(marginheightAttr, value);
338 }
339
340 String HTMLFrameElement::marginWidth() const
341 {
342     return getAttribute(marginwidthAttr);
343 }
344
345 void HTMLFrameElement::setMarginWidth(const String &value)
346 {
347     setAttribute(marginwidthAttr, value);
348 }
349
350 String HTMLFrameElement::name() const
351 {
352     return getAttribute(nameAttr);
353 }
354
355 void HTMLFrameElement::setName(const String &value)
356 {
357     setAttribute(nameAttr, value);
358 }
359
360 void HTMLFrameElement::setNoResize(bool noResize)
361 {
362     setAttribute(noresizeAttr, noResize ? "" : 0);
363 }
364
365 String HTMLFrameElement::scrolling() const
366 {
367     return getAttribute(scrollingAttr);
368 }
369
370 void HTMLFrameElement::setScrolling(const String &value)
371 {
372     setAttribute(scrollingAttr, value);
373 }
374
375 String HTMLFrameElement::src() const
376 {
377     return document()->completeURL(getAttribute(srcAttr));
378 }
379
380 void HTMLFrameElement::setSrc(const String &value)
381 {
382     setAttribute(srcAttr, value);
383 }
384
385 int HTMLFrameElement::frameWidth() const
386 {
387     if (!renderer())
388         return 0;
389     
390     document()->updateLayoutIgnorePendingStylesheets();
391     return renderer()->width();
392 }
393
394 int HTMLFrameElement::frameHeight() const
395 {
396     if (!renderer())
397         return 0;
398     
399     document()->updateLayoutIgnorePendingStylesheets();
400     return renderer()->height();
401 }
402
403 }