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 "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