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/ExceptionState.h" 25 #include "core/dom/ExceptionCode.h" 26 #include "core/loader/FrameLoader.h" 27 #include "core/loader/FrameLoaderClient.h" 28 #include "core/page/Frame.h" 29 #include "core/page/FrameView.h" 30 #include "core/rendering/RenderPart.h" 31 #include "core/svg/SVGDocument.h" 32 #include "weborigin/SecurityOrigin.h" 33 #include "weborigin/SecurityPolicy.h" 34 35 namespace WebCore { 36 37 HTMLFrameOwnerElement::HTMLFrameOwnerElement(const QualifiedName& tagName, Document* document) 38 : HTMLElement(tagName, document) 39 , m_contentFrame(0) 40 , m_sandboxFlags(SandboxNone) 41 { 42 } 43 44 RenderPart* HTMLFrameOwnerElement::renderPart() const 45 { 46 // HTMLObjectElement and HTMLEmbedElement may return arbitrary renderers 47 // when using fallback content. 48 if (!renderer() || !renderer()->isRenderPart()) 49 return 0; 50 return toRenderPart(renderer()); 51 } 52 53 void HTMLFrameOwnerElement::setContentFrame(Frame* frame) 54 { 55 // Make sure we will not end up with two frames referencing the same owner element. 56 ASSERT(!m_contentFrame || m_contentFrame->ownerElement() != this); 57 ASSERT(frame); 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& es) const 117 { 118 Document* doc = contentDocument(); 119 if (doc && doc->isSVGDocument()) 120 return toSVGDocument(doc); 121 // Spec: http://www.w3.org/TR/SVG/struct.html#InterfaceGetSVGDocument 122 es.throwDOMException(NotSupportedError); 123 return 0; 124 } 125 126 bool HTMLFrameOwnerElement::loadOrRedirectSubframe(const KURL& url, const AtomicString& frameName, bool lockBackForwardList) 127 { 128 RefPtr<Frame> parentFrame = document()->frame(); 129 if (contentFrame()) { 130 contentFrame()->navigationScheduler()->scheduleLocationChange(document()->securityOrigin(), url.string(), parentFrame->loader()->outgoingReferrer(), lockBackForwardList); 131 return true; 132 } 133 134 if (!document()->securityOrigin()->canDisplay(url)) { 135 FrameLoader::reportLocalLoadFailed(parentFrame.get(), url.string()); 136 return false; 137 } 138 139 if (!SubframeLoadingDisabler::canLoadFrame(this)) 140 return false; 141 142 String referrer = SecurityPolicy::generateReferrerHeader(document()->referrerPolicy(), url, parentFrame->loader()->outgoingReferrer()); 143 RefPtr<Frame> childFrame = parentFrame->loader()->client()->createFrame(url, frameName, this, referrer, allowScrollingInContentFrame(), marginWidth(), marginHeight()); 144 145 if (!childFrame) { 146 parentFrame->loader()->checkCompleted(); 147 return false; 148 } 149 150 // All new frames will have m_isComplete set to true at this point due to synchronously loading 151 // an empty document in FrameLoader::init(). But many frames will now be starting an 152 // asynchronous load of url, so we set m_isComplete to false and then check if the load is 153 // actually completed below. (Note that we set m_isComplete to false even for synchronous 154 // loads, so that checkCompleted() below won't bail early.) 155 // FIXME: Can we remove this entirely? m_isComplete normally gets set to false when a load is committed. 156 childFrame->loader()->started(); 157 158 RenderObject* renderObject = renderer(); 159 FrameView* view = childFrame->view(); 160 if (renderObject && renderObject->isWidget() && view) 161 toRenderWidget(renderObject)->setWidget(view); 162 163 // Some loads are performed synchronously (e.g., about:blank and loads 164 // cancelled by returning a null ResourceRequest from requestFromDelegate). 165 // In these cases, the synchronous load would have finished 166 // before we could connect the signals, so make sure to send the 167 // completed() signal for the child by hand and mark the load as being 168 // complete. 169 // FIXME: In this case the Frame will have finished loading before 170 // it's being added to the child list. It would be a good idea to 171 // create the child first, then invoke the loader separately. 172 if (childFrame->loader()->state() == FrameStateComplete && !childFrame->loader()->policyDocumentLoader()) 173 childFrame->loader()->checkCompleted(); 174 return true; 175 } 176 177 178 } // namespace WebCore 179