Home | History | Annotate | Download | only in html
      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 "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 
     44 namespace WebCore {
     45 
     46 using namespace HTMLNames;
     47 
     48 HTMLFrameElementBase::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 
     60 bool 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 
     93 void 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 
    112 void 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 
    153 void 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 
    165 void HTMLFrameElementBase::setNameAndOpenURLCallback(Node* n)
    166 {
    167     static_cast<HTMLFrameElementBase*>(n)->setNameAndOpenURL();
    168 }
    169 
    170 void 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 
    180 void HTMLFrameElementBase::removedFromDocument()
    181 {
    182     m_shouldOpenURLAfterAttach = false;
    183 
    184     HTMLFrameOwnerElement::removedFromDocument();
    185 }
    186 
    187 void 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 
    205 KURL HTMLFrameElementBase::location() const
    206 {
    207     return document()->completeURL(getAttribute(srcAttr));
    208 }
    209 
    210 void 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 
    222 bool HTMLFrameElementBase::supportsFocus() const
    223 {
    224     return true;
    225 }
    226 
    227 void HTMLFrameElementBase::setFocus(bool received)
    228 {
    229     HTMLFrameOwnerElement::setFocus(received);
    230     if (Page* page = document()->page())
    231         page->focusController()->setFocusedFrame(received ? contentFrame() : 0);
    232 }
    233 
    234 bool HTMLFrameElementBase::isURLAttribute(Attribute *attr) const
    235 {
    236     return attr->name() == srcAttr;
    237 }
    238 
    239 int HTMLFrameElementBase::width() const
    240 {
    241     if (!renderer())
    242         return 0;
    243 
    244     document()->updateLayoutIgnorePendingStylesheets();
    245     return toRenderBox(renderer())->width();
    246 }
    247 
    248 int HTMLFrameElementBase::height() const
    249 {
    250     if (!renderer())
    251         return 0;
    252 
    253     document()->updateLayoutIgnorePendingStylesheets();
    254     return toRenderBox(renderer())->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_checkAttachedTimer.startOneShot(0);
    265     else
    266         m_checkAttachedTimer.stop();
    267 }
    268 
    269 void HTMLFrameElementBase::checkAttachedTimerFired(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 } // namespace WebCore
    287