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