• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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