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 "CSSHelper.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 "ScriptEventListener.h" 38#include "KURL.h" 39#include "MappedAttribute.h" 40#include "Page.h" 41#include "RenderFrame.h" 42#include "Settings.h" 43 44namespace WebCore { 45 46using namespace HTMLNames; 47 48HTMLFrameElementBase::HTMLFrameElementBase(const QualifiedName& tagName, Document* document) 49 : HTMLFrameOwnerElement(tagName, document) 50 , m_scrolling(ScrollbarAuto) 51 , m_marginWidth(-1) 52 , m_marginHeight(-1) 53 , m_checkAttachedTimer(this, &HTMLFrameElementBase::checkAttachedTimerFired) 54 , m_viewSource(false) 55 , m_shouldOpenURLAfterAttach(false) 56 , m_remainsAliveOnRemovalFromTree(false) 57{ 58} 59 60bool HTMLFrameElementBase::isURLAllowed() const 61{ 62 if (m_URL.isEmpty()) 63 return true; 64 65 const KURL& completeURL = document()->completeURL(m_URL); 66 67 // Don't allow more than 200 total frames in a set. This seems 68 // like a reasonable upper bound, and otherwise mutually recursive 69 // frameset pages can quickly bring the program to its knees with 70 // exponential growth in the number of frames. 71 // FIXME: This limit could be higher, but because WebKit has some 72 // algorithms that happen while loading which appear to be N^2 or 73 // worse in the number of frames, we'll keep it at 200 for now. 74 if (Frame* parentFrame = document()->frame()) { 75 if (parentFrame->page()->frameCount() > 200) 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->loader()->url(), completeURL)) { 84 if (foundSelfReference) 85 return false; 86 foundSelfReference = true; 87 } 88 } 89 90 return true; 91} 92 93void HTMLFrameElementBase::openURL() 94{ 95 ASSERT(!m_frameName.isEmpty()); 96 97 if (!isURLAllowed()) 98 return; 99 100 if (m_URL.isEmpty()) 101 m_URL = blankURL().string(); 102 103 Frame* parentFrame = document()->frame(); 104 if (!parentFrame) 105 return; 106 107 parentFrame->loader()->requestFrame(this, m_URL, m_frameName); 108 if (contentFrame()) 109 contentFrame()->setInViewSourceMode(viewSourceMode()); 110} 111 112void HTMLFrameElementBase::parseMappedAttribute(MappedAttribute *attr) 113{ 114 if (attr->name() == srcAttr) 115 setLocation(deprecatedParseURL(attr->value())); 116 else if (attr->name() == idAttributeName()) { 117 // Important to call through to base for the id attribute so the hasID bit gets set. 118 HTMLFrameOwnerElement::parseMappedAttribute(attr); 119 m_frameName = attr->value(); 120 } else if (attr->name() == nameAttr) { 121 m_frameName = attr->value(); 122 // FIXME: If we are already attached, this doesn't actually change the frame's name. 123 // FIXME: If we are already attached, this doesn't check for frame name 124 // conflicts and generate a unique frame name. 125 } else if (attr->name() == marginwidthAttr) { 126 m_marginWidth = attr->value().toInt(); 127 // FIXME: If we are already attached, this has no effect. 128 } else if (attr->name() == marginheightAttr) { 129 m_marginHeight = attr->value().toInt(); 130 // FIXME: If we are already attached, this has no effect. 131 } else if (attr->name() == scrollingAttr) { 132 // Auto and yes both simply mean "allow scrolling." No means "don't allow scrolling." 133 if (equalIgnoringCase(attr->value(), "auto") || equalIgnoringCase(attr->value(), "yes")) 134 m_scrolling = document()->frameElementsShouldIgnoreScrolling() ? ScrollbarAlwaysOff : ScrollbarAuto; 135 else if (equalIgnoringCase(attr->value(), "no")) 136 m_scrolling = ScrollbarAlwaysOff; 137 // FIXME: If we are already attached, this has no effect. 138 } else if (attr->name() == viewsourceAttr) { 139 m_viewSource = !attr->isNull(); 140 if (contentFrame()) 141 contentFrame()->setInViewSourceMode(viewSourceMode()); 142 } else if (attr->name() == onloadAttr) 143 setAttributeEventListener(eventNames().loadEvent, createAttributeEventListener(this, attr)); 144 else if (attr->name() == onbeforeloadAttr) 145 setAttributeEventListener(eventNames().beforeloadEvent, createAttributeEventListener(this, attr)); 146 else if (attr->name() == onbeforeunloadAttr) { 147 // FIXME: should <frame> elements have beforeunload handlers? 148 setAttributeEventListener(eventNames().beforeunloadEvent, createAttributeEventListener(this, attr)); 149 } else 150 HTMLFrameOwnerElement::parseMappedAttribute(attr); 151} 152 153void HTMLFrameElementBase::setNameAndOpenURL() 154{ 155 m_frameName = getAttribute(nameAttr); 156 if (m_frameName.isNull()) 157 m_frameName = getAttribute(idAttributeName()); 158 159 if (Frame* parentFrame = document()->frame()) 160 m_frameName = parentFrame->tree()->uniqueChildName(m_frameName); 161 162 openURL(); 163} 164 165void HTMLFrameElementBase::setNameAndOpenURLCallback(Node* n) 166{ 167 static_cast<HTMLFrameElementBase*>(n)->setNameAndOpenURL(); 168} 169 170void HTMLFrameElementBase::insertedIntoDocument() 171{ 172 HTMLFrameOwnerElement::insertedIntoDocument(); 173 174 // We delay frame loading until after the render tree is fully constructed. 175 // Othewise, a synchronous load that executed JavaScript would see incorrect 176 // (0) values for the frame's renderer-dependent properties, like width. 177 m_shouldOpenURLAfterAttach = true; 178} 179 180void HTMLFrameElementBase::removedFromDocument() 181{ 182 m_shouldOpenURLAfterAttach = false; 183 184 HTMLFrameOwnerElement::removedFromDocument(); 185} 186 187void HTMLFrameElementBase::attach() 188{ 189 if (m_shouldOpenURLAfterAttach) { 190 m_shouldOpenURLAfterAttach = false; 191 if (!m_remainsAliveOnRemovalFromTree) 192 queuePostAttachCallback(&HTMLFrameElementBase::setNameAndOpenURLCallback, this); 193 } 194 195 setRemainsAliveOnRemovalFromTree(false); 196 197 HTMLFrameOwnerElement::attach(); 198 199 if (RenderPart* renderPart = toRenderPart(renderer())) { 200 if (Frame* frame = contentFrame()) 201 renderPart->setWidget(frame->view()); 202 } 203} 204 205KURL HTMLFrameElementBase::location() const 206{ 207 return document()->completeURL(getAttribute(srcAttr)); 208} 209 210void HTMLFrameElementBase::setLocation(const String& str) 211{ 212 Settings* settings = document()->settings(); 213 if (settings && settings->needsAcrobatFrameReloadingQuirk() && m_URL == str) 214 return; 215 216 m_URL = AtomicString(str); 217 218 if (inDocument()) 219 openURL(); 220} 221 222bool HTMLFrameElementBase::supportsFocus() const 223{ 224 return true; 225} 226 227void HTMLFrameElementBase::setFocus(bool received) 228{ 229 HTMLFrameOwnerElement::setFocus(received); 230 if (Page* page = document()->page()) 231 page->focusController()->setFocusedFrame(received ? contentFrame() : 0); 232} 233 234bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const 235{ 236 return attr->name() == srcAttr; 237} 238 239int HTMLFrameElementBase::width() const 240{ 241 if (!renderer()) 242 return 0; 243 244 document()->updateLayoutIgnorePendingStylesheets(); 245 return toRenderBox(renderer())->width(); 246} 247 248int HTMLFrameElementBase::height() const 249{ 250 if (!renderer()) 251 return 0; 252 253 document()->updateLayoutIgnorePendingStylesheets(); 254 return toRenderBox(renderer())->height(); 255} 256 257void 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_checkAttachedTimer.startOneShot(0); 265 else 266 m_checkAttachedTimer.stop(); 267} 268 269void HTMLFrameElementBase::checkAttachedTimerFired(Timer<HTMLFrameElementBase>*) 270{ 271 ASSERT(!attached()); 272 ASSERT(m_remainsAliveOnRemovalFromTree); 273 274 m_remainsAliveOnRemovalFromTree = false; 275 willRemove(); 276} 277 278void HTMLFrameElementBase::willRemove() 279{ 280 if (m_remainsAliveOnRemovalFromTree) 281 return; 282 283 HTMLFrameOwnerElement::willRemove(); 284} 285 286} // namespace WebCore 287