Home | History | Annotate | Download | only in html
      1 /*
      2  * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  *
     19  */
     20 
     21 #include "config.h"
     22 #include "core/html/HTMLFrameOwnerElement.h"
     23 
     24 #include "bindings/core/v8/ExceptionMessages.h"
     25 #include "bindings/core/v8/ExceptionState.h"
     26 #include "core/accessibility/AXObjectCache.h"
     27 #include "core/dom/ExceptionCode.h"
     28 #include "core/events/Event.h"
     29 #include "core/frame/FrameView.h"
     30 #include "core/frame/LocalFrame.h"
     31 #include "core/loader/FrameLoader.h"
     32 #include "core/loader/FrameLoaderClient.h"
     33 #include "core/rendering/RenderLayer.h"
     34 #include "core/rendering/RenderPart.h"
     35 #include "core/rendering/compositing/RenderLayerCompositor.h"
     36 #include "platform/weborigin/SecurityOrigin.h"
     37 #include "platform/weborigin/SecurityPolicy.h"
     38 
     39 namespace blink {
     40 
     41 typedef HashMap<RefPtr<Widget>, FrameView*> WidgetToParentMap;
     42 static WidgetToParentMap& widgetNewParentMap()
     43 {
     44     DEFINE_STATIC_LOCAL(WidgetToParentMap, map, ());
     45     return map;
     46 }
     47 
     48 WillBeHeapHashCountedSet<RawPtrWillBeMember<Node> >& SubframeLoadingDisabler::disabledSubtreeRoots()
     49 {
     50     DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WillBeHeapHashCountedSet<RawPtrWillBeMember<Node> > >, nodes, (adoptPtrWillBeNoop(new WillBeHeapHashCountedSet<RawPtrWillBeMember<Node> >())));
     51     return *nodes;
     52 }
     53 
     54 static unsigned s_updateSuspendCount = 0;
     55 
     56 HTMLFrameOwnerElement::UpdateSuspendScope::UpdateSuspendScope()
     57 {
     58     ++s_updateSuspendCount;
     59 }
     60 
     61 void HTMLFrameOwnerElement::UpdateSuspendScope::performDeferredWidgetTreeOperations()
     62 {
     63     WidgetToParentMap map;
     64     widgetNewParentMap().swap(map);
     65     WidgetToParentMap::iterator end = map.end();
     66     for (WidgetToParentMap::iterator it = map.begin(); it != end; ++it) {
     67         Widget* child = it->key.get();
     68         ScrollView* currentParent = toScrollView(child->parent());
     69         FrameView* newParent = it->value;
     70         if (newParent != currentParent) {
     71             if (currentParent)
     72                 currentParent->removeChild(child);
     73             if (newParent)
     74                 newParent->addChild(child);
     75         }
     76     }
     77 }
     78 
     79 HTMLFrameOwnerElement::UpdateSuspendScope::~UpdateSuspendScope()
     80 {
     81     ASSERT(s_updateSuspendCount > 0);
     82     if (s_updateSuspendCount == 1)
     83         performDeferredWidgetTreeOperations();
     84     --s_updateSuspendCount;
     85 }
     86 
     87 static void moveWidgetToParentSoon(Widget* child, FrameView* parent)
     88 {
     89     if (!s_updateSuspendCount) {
     90         if (parent)
     91             parent->addChild(child);
     92         else if (toScrollView(child->parent()))
     93             toScrollView(child->parent())->removeChild(child);
     94         return;
     95     }
     96     widgetNewParentMap().set(child, parent);
     97 }
     98 
     99 HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document& document)
    100     : HTMLElement(tagName, document)
    101     , m_contentFrame(nullptr)
    102     , m_widget(nullptr)
    103     , m_sandboxFlags(SandboxNone)
    104 {
    105 }
    106 
    107 RenderPart* HTMLFrameOwnerElement::renderPart() const
    108 {
    109     // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers
    110     // when using fallback content.
    111     if (!renderer() || !renderer()->isRenderPart())
    112         return 0;
    113     return toRenderPart(renderer());
    114 }
    115 
    116 void HTMLFrameOwnerElement::setContentFrame(Frame& frame)
    117 {
    118     // Make sure we will not end up with two frames referencing the same owner element.
    119     ASSERT(!m_contentFrame || m_contentFrame->owner() != this);
    120     // Disconnected frames should not be allowed to load.
    121     ASSERT(inDocument());
    122     m_contentFrame = &frame;
    123 
    124     for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
    125         node->incrementConnectedSubframeCount();
    126 }
    127 
    128 void HTMLFrameOwnerElement::clearContentFrame()
    129 {
    130     if (!m_contentFrame)
    131         return;
    132 
    133     m_contentFrame = nullptr;
    134 
    135     for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode())
    136         node->decrementConnectedSubframeCount();
    137 }
    138 
    139 void HTMLFrameOwnerElement::disconnectContentFrame()
    140 {
    141     // FIXME: Currently we don't do this in removedFrom because this causes an
    142     // unload event in the subframe which could execute script that could then
    143     // reach up into this document and then attempt to look back down. We should
    144     // see if this behavior is really needed as Gecko does not allow this.
    145     if (RefPtrWillBeRawPtr<Frame> frame = contentFrame()) {
    146         frame->detach();
    147 #if ENABLE(OILPAN)
    148         // FIXME: Oilpan: the plugin container is released and finalized here
    149         // in order to work around the current inability to make the plugin
    150         // container a FrameDestructionObserver (it needs to effectively be on
    151         // the heap, and Widget isn't). Hence, release it here while its
    152         // frame reference is still valid.
    153         if (m_widget && m_widget->isPluginContainer())
    154             m_widget = nullptr;
    155 #endif
    156         frame->disconnectOwnerElement();
    157     }
    158 }
    159 
    160 HTMLFrameOwnerElement::~HTMLFrameOwnerElement()
    161 {
    162 #if ENABLE(OILPAN)
    163     // An owner must by now have been informed of detachment
    164     // when the frame was closed.
    165     ASSERT(!m_contentFrame);
    166 #else
    167     if (m_contentFrame)
    168         m_contentFrame->disconnectOwnerElement();
    169 #endif
    170 }
    171 
    172 Document* HTMLFrameOwnerElement::contentDocument() const
    173 {
    174     return (m_contentFrame && m_contentFrame->isLocalFrame()) ? toLocalFrame(m_contentFrame)->document() : 0;
    175 }
    176 
    177 LocalDOMWindow* HTMLFrameOwnerElement::contentWindow() const
    178 {
    179     return m_contentFrame ? m_contentFrame->domWindow() : 0;
    180 }
    181 
    182 void HTMLFrameOwnerElement::setSandboxFlags(SandboxFlags flags)
    183 {
    184     m_sandboxFlags = flags;
    185 }
    186 
    187 bool HTMLFrameOwnerElement::isKeyboardFocusable() const
    188 {
    189     return m_contentFrame && HTMLElement::isKeyboardFocusable();
    190 }
    191 
    192 void HTMLFrameOwnerElement::dispatchLoad()
    193 {
    194     dispatchEvent(Event::create(EventTypeNames::load));
    195 }
    196 
    197 Document* HTMLFrameOwnerElement::getSVGDocument(ExceptionState& exceptionState) const
    198 {
    199     Document* doc = contentDocument();
    200     if (doc && doc->isSVGDocument())
    201         return doc;
    202     return 0;
    203 }
    204 
    205 void HTMLFrameOwnerElement::setWidget(PassRefPtr<Widget> widget)
    206 {
    207     if (widget == m_widget)
    208         return;
    209 
    210     if (m_widget) {
    211         if (m_widget->parent())
    212             moveWidgetToParentSoon(m_widget.get(), 0);
    213         m_widget = nullptr;
    214     }
    215 
    216     m_widget = widget;
    217 
    218     RenderWidget* renderWidget = toRenderWidget(renderer());
    219     if (!renderWidget)
    220         return;
    221 
    222     if (m_widget) {
    223         renderWidget->updateOnWidgetChange();
    224 
    225         ASSERT(document().view() == renderWidget->frameView());
    226         ASSERT(renderWidget->frameView());
    227         moveWidgetToParentSoon(m_widget.get(), renderWidget->frameView());
    228     }
    229 
    230     if (AXObjectCache* cache = document().existingAXObjectCache())
    231         cache->childrenChanged(renderWidget);
    232 }
    233 
    234 Widget* HTMLFrameOwnerElement::ownedWidget() const
    235 {
    236     return m_widget.get();
    237 }
    238 
    239 bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const AtomicString& frameName, bool lockBackForwardList)
    240 {
    241     RefPtrWillBeRawPtr<LocalFrame> parentFrame = document().frame();
    242     // FIXME(kenrb): The necessary semantics for RemoteFrames have not been worked out yet, but this will likely need some logic to handle them.
    243     if (contentFrame() && contentFrame()->isLocalFrame()) {
    244         toLocalFrame(contentFrame())->navigationScheduler().scheduleLocationChange(&document(), url.string(), Referrer(document().outgoingReferrer(), document().referrerPolicy()), lockBackForwardList);
    245         return true;
    246     }
    247 
    248     if (!document().securityOrigin()->canDisplay(url)) {
    249         FrameLoader::reportLocalLoadFailed(parentFrame.get(), url.string());
    250         return false;
    251     }
    252 
    253     if (!SubframeLoadingDisabler::canLoadFrame(*this))
    254         return false;
    255 
    256     String referrer = SecurityPolicy::generateReferrerHeader(document().referrerPolicy(), url, document().outgoingReferrer());
    257     return parentFrame->loader().client()->createFrame(url, frameName, Referrer(referrer, document().referrerPolicy()), this);
    258 }
    259 
    260 void HTMLFrameOwnerElement::trace(Visitor* visitor)
    261 {
    262     visitor->trace(m_contentFrame);
    263     HTMLElement::trace(visitor);
    264     FrameOwner::trace(visitor);
    265 }
    266 
    267 
    268 } // namespace blink
    269