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 "web/OpenedFrameTracker.h"
10#include "web/WebLocalFrameImpl.h"
11#include "web/WebRemoteFrameImpl.h"
12#include <algorithm>
13
14
15namespace blink {
16
17WebCore::Frame* toWebCoreFrame(const WebFrame* frame)
18{
19    if (!frame)
20        return 0;
21
22    return frame->isWebLocalFrame()
23        ? static_cast<WebCore::Frame*>(toWebLocalFrameImpl(frame)->frame())
24        : toWebRemoteFrameImpl(frame)->frame();
25}
26
27void WebFrame::swap(WebFrame* frame)
28{
29    using std::swap;
30
31    if (m_parent) {
32        if (m_parent->m_firstChild == this)
33            m_parent->m_firstChild = frame;
34        if (m_parent->m_lastChild == this)
35            m_parent->m_lastChild = frame;
36        swap(m_parent, frame->m_parent);
37    }
38    if (m_previousSibling) {
39        m_previousSibling->m_nextSibling = frame;
40        swap(m_previousSibling, frame->m_previousSibling);
41    }
42    if (m_nextSibling) {
43        m_nextSibling->m_previousSibling = frame;
44        swap(m_nextSibling, frame->m_nextSibling);
45    }
46    if (m_opener) {
47        m_opener->m_openedFrameTracker->remove(this);
48        m_opener->m_openedFrameTracker->add(frame);
49        swap(m_opener, frame->m_opener);
50    }
51    if (!m_openedFrameTracker->isEmpty()) {
52        m_openedFrameTracker->updateOpener(frame);
53        frame->m_openedFrameTracker.reset(m_openedFrameTracker.release());
54    }
55}
56
57WebFrame* WebFrame::opener() const
58{
59    return m_opener;
60}
61
62void WebFrame::setOpener(WebFrame* opener)
63{
64    if (m_opener)
65        m_opener->m_openedFrameTracker->remove(this);
66    if (opener)
67        opener->m_openedFrameTracker->add(this);
68    m_opener = opener;
69}
70
71void WebFrame::appendChild(WebFrame* child)
72{
73    // FIXME: Original code asserts that the frames have the same Page. We
74    // should add an equivalent check... figure out what.
75    child->m_parent = this;
76    WebFrame* oldLast = m_lastChild;
77    m_lastChild = child;
78
79    if (oldLast) {
80        child->m_previousSibling = oldLast;
81        oldLast->m_nextSibling = child;
82    } else {
83        m_firstChild = child;
84    }
85
86    toWebCoreFrame(this)->tree().invalidateScopedChildCount();
87}
88
89void WebFrame::removeChild(WebFrame* child)
90{
91    child->m_parent = 0;
92
93    if (m_firstChild == child)
94        m_firstChild = child->m_nextSibling;
95    else
96        child->m_previousSibling->m_nextSibling = child->m_nextSibling;
97
98    if (m_lastChild == child)
99        m_lastChild = child->m_previousSibling;
100    else
101        child->m_nextSibling->m_previousSibling = child->m_previousSibling;
102
103    child->m_previousSibling = child->m_nextSibling = 0;
104
105    toWebCoreFrame(this)->tree().invalidateScopedChildCount();
106}
107
108WebFrame* WebFrame::parent() const
109{
110    return m_parent;
111}
112
113WebFrame* WebFrame::top() const
114{
115    WebFrame* frame = const_cast<WebFrame*>(this);
116    for (WebFrame* parent = frame; parent; parent = parent->m_parent)
117        frame = parent;
118    return frame;
119}
120
121WebFrame* WebFrame::firstChild() const
122{
123    return m_firstChild;
124}
125
126WebFrame* WebFrame::lastChild() const
127{
128    return m_lastChild;
129}
130
131WebFrame* WebFrame::previousSibling() const
132{
133    return m_previousSibling;
134}
135
136WebFrame* WebFrame::nextSibling() const
137{
138    return m_nextSibling;
139}
140
141WebFrame* WebFrame::traversePrevious(bool wrap) const
142{
143    WebCore::Frame* frame = toWebCoreFrame(this);
144    if (!frame)
145        return 0;
146    return fromFrame(frame->tree().traversePreviousWithWrap(wrap));
147}
148
149WebFrame* WebFrame::traverseNext(bool wrap) const
150{
151    WebCore::Frame* frame = toWebCoreFrame(this);
152    if (!frame)
153        return 0;
154    return fromFrame(frame->tree().traverseNextWithWrap(wrap));
155}
156
157WebFrame* WebFrame::findChildByName(const WebString& name) const
158{
159    WebCore::Frame* frame = toWebCoreFrame(this);
160    if (!frame)
161        return 0;
162    // FIXME: It's not clear this should ever be called to find a remote frame.
163    // Perhaps just disallow that completely?
164    return fromFrame(frame->tree().child(name));
165}
166
167WebFrame* WebFrame::fromFrame(WebCore::Frame* frame)
168{
169    if (!frame)
170        return 0;
171
172    if (frame->isLocalFrame())
173        return WebLocalFrameImpl::fromFrame(toLocalFrame(*frame));
174    return WebRemoteFrameImpl::fromFrame(toRemoteFrame(*frame));
175}
176
177WebFrame::WebFrame()
178    : m_parent(0)
179    , m_previousSibling(0)
180    , m_nextSibling(0)
181    , m_firstChild(0)
182    , m_lastChild(0)
183    , m_opener(0)
184    , m_openedFrameTracker(new OpenedFrameTracker)
185{
186}
187
188WebFrame::~WebFrame()
189{
190    m_openedFrameTracker.reset(0);
191}
192
193} // namespace blink
194