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/v8/ExceptionMessages.h" 25 #include "bindings/v8/ExceptionState.h" 26 #include "core/dom/ExceptionCode.h" 27 #include "core/loader/FrameLoader.h" 28 #include "core/loader/FrameLoaderClient.h" 29 #include "core/frame/Frame.h" 30 #include "core/frame/FrameView.h" 31 #include "core/rendering/RenderPart.h" 32 #include "core/svg/SVGDocument.h" 33 #include "platform/weborigin/SecurityOrigin.h" 34 #include "platform/weborigin/SecurityPolicy.h" 35 36 namespace WebCore { 37 38 HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document& document) 39 : HTMLElement(tagName, document) 40 , m_contentFrame(0) 41 , m_sandboxFlags(SandboxNone) 42 { 43 } 44 45 RenderPart* HTMLFrameOwnerElement::renderPart() const 46 { 47 // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers 48 // when using fallback content. 49 if (!renderer() || !renderer()->isRenderPart()) 50 return 0; 51 return toRenderPart(renderer()); 52 } 53 54 void HTMLFrameOwnerElement::setContentFrame(Frame& frame) 55 { 56 // Make sure we will not end up with two frames referencing the same owner element. 57 ASSERT(!m_contentFrame || m_contentFrame->ownerElement() != this); 58 // Disconnected frames should not be allowed to load. 59 ASSERT(inDocument()); 60 m_contentFrame = &frame; 61 62 for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode()) 63 node->incrementConnectedSubframeCount(); 64 } 65 66 void HTMLFrameOwnerElement::clearContentFrame() 67 { 68 if (!m_contentFrame) 69 return; 70 71 m_contentFrame = 0; 72 73 for (ContainerNode* node = this; node; node = node->parentOrShadowHostNode()) 74 node->decrementConnectedSubframeCount(); 75 } 76 77 void HTMLFrameOwnerElement::disconnectContentFrame() 78 { 79 // FIXME: Currently we don't do this in removedFrom because this causes an 80 // unload event in the subframe which could execute script that could then 81 // reach up into this document and then attempt to look back down. We should 82 // see if this behavior is really needed as Gecko does not allow this. 83 if (Frame* frame = contentFrame()) { 84 RefPtr<Frame> protect(frame); 85 frame->loader().frameDetached(); 86 frame->disconnectOwnerElement(); 87 } 88 } 89 90 HTMLFrameOwnerElement::~HTMLFrameOwnerElement() 91 { 92 if (m_contentFrame) 93 m_contentFrame->disconnectOwnerElement(); 94 } 95 96 Document* HTMLFrameOwnerElement::contentDocument() const 97 { 98 return m_contentFrame ? m_contentFrame->document() : 0; 99 } 100 101 DOMWindow* HTMLFrameOwnerElement::contentWindow() const 102 { 103 return m_contentFrame ? m_contentFrame->domWindow() : 0; 104 } 105 106 void HTMLFrameOwnerElement::setSandboxFlags(SandboxFlags flags) 107 { 108 m_sandboxFlags = flags; 109 } 110 111 bool HTMLFrameOwnerElement::isKeyboardFocusable() const 112 { 113 return m_contentFrame && HTMLElement::isKeyboardFocusable(); 114 } 115 116 SVGDocument* HTMLFrameOwnerElement::getSVGDocument(ExceptionState& exceptionState) const 117 { 118 Document* doc = contentDocument(); 119 if (doc && doc->isSVGDocument()) 120 return toSVGDocument(doc); 121 return 0; 122 } 123 124 bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const AtomicString& frameName, bool lockBackForwardList) 125 { 126 RefPtr<Frame> parentFrame = document().frame(); 127 if (contentFrame()) { 128 contentFrame()->navigationScheduler().scheduleLocationChange(&document(), url.string(), document().outgoingReferrer(), lockBackForwardList); 129 return true; 130 } 131 132 if (!document().securityOrigin()->canDisplay(url)) { 133 FrameLoader::reportLocalLoadFailed(parentFrame.get(), url.string()); 134 return false; 135 } 136 137 if (!SubframeLoadingDisabler::canLoadFrame(*this)) 138 return false; 139 140 String referrer = SecurityPolicy::generateReferrerHeader(document().referrerPolicy(), url, document().outgoingReferrer()); 141 RefPtr<Frame> childFrame = parentFrame->loader().client()->createFrame(url, frameName, referrer, this); 142 143 if (!childFrame) { 144 parentFrame->loader().checkCompleted(); 145 return false; 146 } 147 148 // All new frames will have m_isComplete set to true at this point due to synchronously loading 149 // an empty document in FrameLoader::init(). But many frames will now be starting an 150 // asynchronous load of url, so we set m_isComplete to false and then check if the load is 151 // actually completed below. (Note that we set m_isComplete to false even for synchronous 152 // loads, so that checkCompleted() below won't bail early.) 153 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed. 154 childFrame->loader().started(); 155 156 RenderObject* renderObject = renderer(); 157 FrameView* view = childFrame->view(); 158 if (renderObject && renderObject->isWidget() && view) 159 toRenderWidget(renderObject)->setWidget(view); 160 161 // Some loads are performed synchronously (e.g., about:blank and loads 162 // cancelled by returning a null ResourceRequest from requestFromDelegate). 163 // In these cases, the synchronous load would have finished 164 // before we could connect the signals, so make sure to send the 165 // completed() signal for the child by hand and mark the load as being 166 // complete. 167 // FIXME: In this case the Frame will have finished loading before 168 // it's being added to the child list. It would be a good idea to 169 // create the child first, then invoke the loader separately. 170 if (childFrame->loader().state() == FrameStateComplete && !childFrame->loader().policyDocumentLoader()) 171 childFrame->loader().checkCompleted(); 172 return true; 173 } 174 175 176 } // namespace WebCore 177