1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "config.h" 6 #include "public/web/WebFrame.h" 7 8 #include "core/frame/RemoteFrame.h" 9 #include "core/html/HTMLFrameOwnerElement.h" 10 #include "platform/UserGestureIndicator.h" 11 #include "platform/heap/Handle.h" 12 #include "web/OpenedFrameTracker.h" 13 #include "web/WebLocalFrameImpl.h" 14 #include "web/WebRemoteFrameImpl.h" 15 #include <algorithm> 16 17 namespace blink { 18 19 Frame* toCoreFrame(const WebFrame* frame) 20 { 21 if (!frame) 22 return 0; 23 24 return frame->isWebLocalFrame() 25 ? static_cast<Frame*>(toWebLocalFrameImpl(frame)->frame()) 26 : toWebRemoteFrameImpl(frame)->frame(); 27 } 28 29 bool WebFrame::swap(WebFrame* frame) 30 { 31 using std::swap; 32 RefPtrWillBeRawPtr<Frame> oldFrame = toCoreFrame(this); 33 34 // All child frames must be detached first. 35 oldFrame->detachChildren(); 36 37 // If the frame has been detached during detaching its children, return 38 // immediately. 39 // FIXME: There is no unit test for this condition, so one needs to be 40 // written. 41 if (!oldFrame->host()) 42 return false; 43 44 // The frame being swapped in should not have a Frame associated 45 // with it yet. 46 ASSERT(!toCoreFrame(frame)); 47 48 if (m_parent) { 49 if (m_parent->m_firstChild == this) 50 m_parent->m_firstChild = frame; 51 if (m_parent->m_lastChild == this) 52 m_parent->m_lastChild = frame; 53 swap(m_parent, frame->m_parent); 54 } 55 56 if (m_previousSibling) { 57 m_previousSibling->m_nextSibling = frame; 58 swap(m_previousSibling, frame->m_previousSibling); 59 } 60 if (m_nextSibling) { 61 m_nextSibling->m_previousSibling = frame; 62 swap(m_nextSibling, frame->m_nextSibling); 63 } 64 65 if (m_opener) { 66 m_opener->m_openedFrameTracker->remove(this); 67 m_opener->m_openedFrameTracker->add(frame); 68 swap(m_opener, frame->m_opener); 69 } 70 if (!m_openedFrameTracker->isEmpty()) { 71 m_openedFrameTracker->updateOpener(frame); 72 frame->m_openedFrameTracker.reset(m_openedFrameTracker.release()); 73 } 74 75 // Finally, clone the state of the current Frame into one matching 76 // the type of the passed in WebFrame. 77 // FIXME: This is a bit clunky; this results in pointless decrements and 78 // increments of connected subframes. 79 FrameOwner* owner = oldFrame->owner(); 80 oldFrame->disconnectOwnerElement(); 81 if (frame->isWebLocalFrame()) { 82 toWebLocalFrameImpl(frame)->initializeCoreFrame(oldFrame->host(), owner, oldFrame->tree().name(), nullAtom); 83 } else { 84 toWebRemoteFrameImpl(frame)->initializeCoreFrame(oldFrame->host(), owner, oldFrame->tree().name()); 85 } 86 87 return true; 88 } 89 90 void WebFrame::detach() 91 { 92 toCoreFrame(this)->detach(); 93 } 94 95 WebFrame* WebFrame::opener() const 96 { 97 return m_opener; 98 } 99 100 void WebFrame::setOpener(WebFrame* opener) 101 { 102 if (m_opener) 103 m_opener->m_openedFrameTracker->remove(this); 104 if (opener) 105 opener->m_openedFrameTracker->add(this); 106 m_opener = opener; 107 } 108 109 void WebFrame::appendChild(WebFrame* child) 110 { 111 // FIXME: Original code asserts that the frames have the same Page. We 112 // should add an equivalent check... figure out what. 113 child->m_parent = this; 114 WebFrame* oldLast = m_lastChild; 115 m_lastChild = child; 116 117 if (oldLast) { 118 child->m_previousSibling = oldLast; 119 oldLast->m_nextSibling = child; 120 } else { 121 m_firstChild = child; 122 } 123 124 toCoreFrame(this)->tree().invalidateScopedChildCount(); 125 } 126 127 void WebFrame::removeChild(WebFrame* child) 128 { 129 child->m_parent = 0; 130 131 if (m_firstChild == child) 132 m_firstChild = child->m_nextSibling; 133 else 134 child->m_previousSibling->m_nextSibling = child->m_nextSibling; 135 136 if (m_lastChild == child) 137 m_lastChild = child->m_previousSibling; 138 else 139 child->m_nextSibling->m_previousSibling = child->m_previousSibling; 140 141 child->m_previousSibling = child->m_nextSibling = 0; 142 143 toCoreFrame(this)->tree().invalidateScopedChildCount(); 144 } 145 146 WebFrame* WebFrame::parent() const 147 { 148 return m_parent; 149 } 150 151 WebFrame* WebFrame::top() const 152 { 153 WebFrame* frame = const_cast<WebFrame*>(this); 154 for (WebFrame* parent = frame; parent; parent = parent->m_parent) 155 frame = parent; 156 return frame; 157 } 158 159 WebFrame* WebFrame::firstChild() const 160 { 161 return m_firstChild; 162 } 163 164 WebFrame* WebFrame::lastChild() const 165 { 166 return m_lastChild; 167 } 168 169 WebFrame* WebFrame::previousSibling() const 170 { 171 return m_previousSibling; 172 } 173 174 WebFrame* WebFrame::nextSibling() const 175 { 176 return m_nextSibling; 177 } 178 179 WebFrame* WebFrame::traversePrevious(bool wrap) const 180 { 181 if (Frame* frame = toCoreFrame(this)) 182 return fromFrame(frame->tree().traversePreviousWithWrap(wrap)); 183 return 0; 184 } 185 186 WebFrame* WebFrame::traverseNext(bool wrap) const 187 { 188 if (Frame* frame = toCoreFrame(this)) 189 return fromFrame(frame->tree().traverseNextWithWrap(wrap)); 190 return 0; 191 } 192 193 WebFrame* WebFrame::findChildByName(const WebString& name) const 194 { 195 Frame* frame = toCoreFrame(this); 196 if (!frame) 197 return 0; 198 // FIXME: It's not clear this should ever be called to find a remote frame. 199 // Perhaps just disallow that completely? 200 return fromFrame(frame->tree().child(name)); 201 } 202 203 WebFrame* WebFrame::fromFrame(Frame* frame) 204 { 205 if (!frame) 206 return 0; 207 208 if (frame->isLocalFrame()) 209 return WebLocalFrameImpl::fromFrame(toLocalFrame(*frame)); 210 return WebRemoteFrameImpl::fromFrame(toRemoteFrame(*frame)); 211 } 212 213 WebFrame::WebFrame() 214 : m_parent(0) 215 , m_previousSibling(0) 216 , m_nextSibling(0) 217 , m_firstChild(0) 218 , m_lastChild(0) 219 , m_opener(0) 220 , m_openedFrameTracker(new OpenedFrameTracker) 221 { 222 } 223 224 WebFrame::~WebFrame() 225 { 226 m_openedFrameTracker.reset(0); 227 } 228 229 void WebFrame::traceChildren(Visitor* visitor, WebFrame* frame) 230 { 231 #if ENABLE(OILPAN) 232 // Trace the children frames. 233 WebFrame* child = frame ? frame->firstChild() : 0; 234 while (child) { 235 if (child->isWebLocalFrame()) 236 visitor->trace(toWebLocalFrameImpl(child)); 237 else 238 visitor->trace(toWebRemoteFrameImpl(child)); 239 240 child = child->nextSibling(); 241 } 242 #endif 243 } 244 245 } // namespace blink 246