1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2000 Simon Hausmann (hausmann (at) kde.org) 5 * (C) 2001 Dirk Mueller (mueller (at) 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 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 61 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 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 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 151 void HTMLFrameElementBase::setNameAndOpenURL() 152 { 153 m_frameName = getAttribute(nameAttr); 154 if (m_frameName.isNull()) 155 m_frameName = getIdAttribute(); 156 openURL(); 157 } 158 159 void HTMLFrameElementBase::updateOnReparenting() 160 { 161 ASSERT(m_remainsAliveOnRemovalFromTree); 162 163 if (Frame* frame = contentFrame()) 164 frame->transferChildFrameToNewDocument(); 165 } 166 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 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 203 KURL HTMLFrameElementBase::location() const 204 { 205 return document()->completeURL(getAttribute(srcAttr)); 206 } 207 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 220 bool HTMLFrameElementBase::supportsFocus() const 221 { 222 return true; 223 } 224 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 236 bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const 237 { 238 return attr->name() == srcAttr; 239 } 240 241 int HTMLFrameElementBase::width() const 242 { 243 document()->updateLayoutIgnorePendingStylesheets(); 244 if (!renderBox()) 245 return 0; 246 return renderBox()->width(); 247 } 248 249 int HTMLFrameElementBase::height() const 250 { 251 document()->updateLayoutIgnorePendingStylesheets(); 252 if (!renderBox()) 253 return 0; 254 return renderBox()->height(); 255 } 256 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 269 void HTMLFrameElementBase::checkInDocumentTimerFired(Timer<HTMLFrameElementBase>*) 270 { 271 ASSERT(!attached()); 272 ASSERT(m_remainsAliveOnRemovalFromTree); 273 274 m_remainsAliveOnRemovalFromTree = false; 275 willRemove(); 276 } 277 278 void HTMLFrameElementBase::willRemove() 279 { 280 if (m_remainsAliveOnRemovalFromTree) 281 return; 282 283 HTMLFrameOwnerElement::willRemove(); 284 } 285 286 #if ENABLE(FULLSCREEN_API) 287 bool HTMLFrameElementBase::allowFullScreen() const 288 { 289 return hasAttribute(webkitallowfullscreenAttr); 290 } 291 #endif 292 293 } // namespace WebCore 294