• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3  * Copyright (C) 2006 Apple Computer, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "config.h"
22 #include "core/page/FrameTree.h"
23 
24 #include "core/dom/Document.h"
25 #include "core/frame/FrameClient.h"
26 #include "core/frame/FrameView.h"
27 #include "core/frame/LocalFrame.h"
28 #include "core/frame/RemoteFrame.h"
29 #include "core/frame/RemoteFrameView.h"
30 #include "core/page/Page.h"
31 #include "wtf/Vector.h"
32 #include "wtf/text/CString.h"
33 #include "wtf/text/StringBuilder.h"
34 
35 using std::swap;
36 
37 namespace blink {
38 
39 namespace {
40 
41 const unsigned invalidChildCount = ~0U;
42 
43 } // namespace
44 
FrameTree(Frame * thisFrame)45 FrameTree::FrameTree(Frame* thisFrame)
46     : m_thisFrame(thisFrame)
47     , m_scopedChildCount(invalidChildCount)
48 {
49 }
50 
~FrameTree()51 FrameTree::~FrameTree()
52 {
53 #if !ENABLE(OILPAN)
54     // FIXME: Why is this here? Doesn't this parallel what we already do in ~LocalFrame?
55     for (Frame* child = firstChild(); child; child = child->tree().nextSibling()) {
56         if (child->isLocalFrame())
57             toLocalFrame(child)->setView(nullptr);
58         else if (child->isRemoteFrame())
59             toRemoteFrame(child)->setView(nullptr);
60     }
61 #endif
62 }
63 
setName(const AtomicString & name,const AtomicString & fallbackName)64 void FrameTree::setName(const AtomicString& name, const AtomicString& fallbackName)
65 {
66     m_name = name;
67     if (!parent()) {
68         m_uniqueName = name;
69         return;
70     }
71     m_uniqueName = AtomicString(); // Remove our old frame name so it's not considered in uniqueChildName.
72     m_uniqueName = parent()->tree().uniqueChildName(name.isEmpty() ? fallbackName : name);
73 }
74 
parent() const75 Frame* FrameTree::parent() const
76 {
77     if (!m_thisFrame->client())
78         return 0;
79     return m_thisFrame->client()->parent();
80 }
81 
top() const82 Frame* FrameTree::top() const
83 {
84     // FIXME: top() should never return null, so here are some hacks to deal
85     // with EmptyFrameLoaderClient and cases where the frame is detached
86     // already...
87     if (!m_thisFrame->client())
88         return m_thisFrame;
89     Frame* candidate = m_thisFrame->client()->top();
90     return candidate ? candidate : m_thisFrame.get();
91 }
92 
previousSibling() const93 Frame* FrameTree::previousSibling() const
94 {
95     if (!m_thisFrame->client())
96         return 0;
97     return m_thisFrame->client()->previousSibling();
98 }
99 
nextSibling() const100 Frame* FrameTree::nextSibling() const
101 {
102     if (!m_thisFrame->client())
103         return 0;
104     return m_thisFrame->client()->nextSibling();
105 }
106 
firstChild() const107 Frame* FrameTree::firstChild() const
108 {
109     if (!m_thisFrame->client())
110         return 0;
111     return m_thisFrame->client()->firstChild();
112 }
113 
lastChild() const114 Frame* FrameTree::lastChild() const
115 {
116     if (!m_thisFrame->client())
117         return 0;
118     return m_thisFrame->client()->lastChild();
119 }
120 
uniqueNameExists(const AtomicString & name) const121 bool FrameTree::uniqueNameExists(const AtomicString& name) const
122 {
123     for (Frame* frame = top(); frame; frame = frame->tree().traverseNext()) {
124         if (frame->tree().uniqueName() == name)
125             return true;
126     }
127     return false;
128 }
129 
uniqueChildName(const AtomicString & requestedName) const130 AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const
131 {
132     if (!requestedName.isEmpty() && !uniqueNameExists(requestedName) && requestedName != "_blank")
133         return requestedName;
134 
135     // Create a repeatable name for a child about to be added to us. The name must be
136     // unique within the frame tree. The string we generate includes a "path" of names
137     // from the root frame down to us. For this path to be unique, each set of siblings must
138     // contribute a unique name to the path, which can't collide with any HTML-assigned names.
139     // We generate this path component by index in the child list along with an unlikely
140     // frame name that can't be set in HTML because it collides with comment syntax.
141 
142     const char framePathPrefix[] = "<!--framePath ";
143     const int framePathPrefixLength = 14;
144     const int framePathSuffixLength = 3;
145 
146     // Find the nearest parent that has a frame with a path in it.
147     Vector<Frame*, 16> chain;
148     Frame* frame;
149     for (frame = m_thisFrame; frame; frame = frame->tree().parent()) {
150         if (frame->tree().uniqueName().startsWith(framePathPrefix))
151             break;
152         chain.append(frame);
153     }
154     StringBuilder name;
155     name.append(framePathPrefix);
156     if (frame) {
157         name.append(frame->tree().uniqueName().string().substring(framePathPrefixLength,
158             frame->tree().uniqueName().length() - framePathPrefixLength - framePathSuffixLength));
159     }
160     for (int i = chain.size() - 1; i >= 0; --i) {
161         frame = chain[i];
162         name.append('/');
163         name.append(frame->tree().uniqueName());
164     }
165 
166     name.appendLiteral("/<!--frame");
167     name.appendNumber(childCount() - 1);
168     name.appendLiteral("-->-->");
169 
170     return name.toAtomicString();
171 }
172 
scopedChild(unsigned index) const173 Frame* FrameTree::scopedChild(unsigned index) const
174 {
175     if (!m_thisFrame->isLocalFrame())
176         return 0;
177     TreeScope* scope = toLocalFrame(m_thisFrame)->document();
178     if (!scope)
179         return 0;
180 
181     unsigned scopedIndex = 0;
182     for (Frame* result = firstChild(); result; result = result->tree().nextSibling()) {
183         if (result->isLocalFrame() && toLocalFrame(result)->inScope(scope)) {
184             if (scopedIndex == index)
185                 return result;
186             scopedIndex++;
187         }
188     }
189 
190     return 0;
191 }
192 
scopedChild(const AtomicString & name) const193 Frame* FrameTree::scopedChild(const AtomicString& name) const
194 {
195     if (!m_thisFrame->isLocalFrame())
196         return 0;
197 
198     TreeScope* scope = toLocalFrame(m_thisFrame)->document();
199     if (!scope)
200         return 0;
201 
202     for (Frame* child = firstChild(); child; child = child->tree().nextSibling())
203         if (child->tree().name() == name && child->isLocalFrame() && toLocalFrame(child)->inScope(scope))
204             return child;
205     return 0;
206 }
207 
scopedChildCount(TreeScope * scope) const208 inline unsigned FrameTree::scopedChildCount(TreeScope* scope) const
209 {
210     if (!scope)
211         return 0;
212 
213     unsigned scopedCount = 0;
214     for (Frame* result = firstChild(); result; result = result->tree().nextSibling()) {
215         if (result->isLocalFrame() && toLocalFrame(result)->inScope(scope))
216             scopedCount++;
217     }
218 
219     return scopedCount;
220 }
221 
scopedChildCount() const222 unsigned FrameTree::scopedChildCount() const
223 {
224     if (m_scopedChildCount == invalidChildCount)
225         m_scopedChildCount = scopedChildCount(toLocalFrame(m_thisFrame)->document());
226     return m_scopedChildCount;
227 }
228 
invalidateScopedChildCount()229 void FrameTree::invalidateScopedChildCount()
230 {
231     m_scopedChildCount = invalidChildCount;
232 }
233 
childCount() const234 unsigned FrameTree::childCount() const
235 {
236     unsigned count = 0;
237     for (Frame* result = firstChild(); result; result = result->tree().nextSibling())
238         ++count;
239     return count;
240 }
241 
child(const AtomicString & name) const242 Frame* FrameTree::child(const AtomicString& name) const
243 {
244     for (Frame* child = firstChild(); child; child = child->tree().nextSibling())
245         if (child->tree().name() == name)
246             return child;
247     return 0;
248 }
249 
find(const AtomicString & name) const250 Frame* FrameTree::find(const AtomicString& name) const
251 {
252     if (name == "_self" || name == "_current" || name.isEmpty())
253         return m_thisFrame;
254 
255     if (name == "_top")
256         return top();
257 
258     if (name == "_parent")
259         return parent() ? parent() : m_thisFrame.get();
260 
261     // Since "_blank" should never be any frame's name, the following just amounts to an optimization.
262     if (name == "_blank")
263         return 0;
264 
265     // Search subtree starting with this frame first.
266     for (Frame* frame = m_thisFrame; frame; frame = frame->tree().traverseNext(m_thisFrame))
267         if (frame->tree().name() == name)
268             return frame;
269 
270     // Search the entire tree for this page next.
271     Page* page = m_thisFrame->page();
272 
273     // The frame could have been detached from the page, so check it.
274     if (!page)
275         return 0;
276 
277     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext())
278         if (frame->tree().name() == name)
279             return frame;
280 
281     // Search the entire tree of each of the other pages in this namespace.
282     // FIXME: Is random order OK?
283     const HashSet<Page*>& pages = Page::ordinaryPages();
284     HashSet<Page*>::const_iterator end = pages.end();
285     for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
286         Page* otherPage = *it;
287         if (otherPage != page) {
288             for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree().traverseNext()) {
289                 if (frame->tree().name() == name)
290                     return frame;
291             }
292         }
293     }
294 
295     return 0;
296 }
297 
isDescendantOf(const Frame * ancestor) const298 bool FrameTree::isDescendantOf(const Frame* ancestor) const
299 {
300     if (!ancestor)
301         return false;
302 
303     if (m_thisFrame->page() != ancestor->page())
304         return false;
305 
306     for (Frame* frame = m_thisFrame; frame; frame = frame->tree().parent())
307         if (frame == ancestor)
308             return true;
309     return false;
310 }
311 
traverseNext(const Frame * stayWithin) const312 Frame* FrameTree::traverseNext(const Frame* stayWithin) const
313 {
314     Frame* child = firstChild();
315     if (child) {
316         ASSERT(!stayWithin || child->tree().isDescendantOf(stayWithin));
317         return child;
318     }
319 
320     if (m_thisFrame == stayWithin)
321         return 0;
322 
323     Frame* sibling = nextSibling();
324     if (sibling) {
325         ASSERT(!stayWithin || sibling->tree().isDescendantOf(stayWithin));
326         return sibling;
327     }
328 
329     Frame* frame = m_thisFrame;
330     while (!sibling && (!stayWithin || frame->tree().parent() != stayWithin)) {
331         frame = frame->tree().parent();
332         if (!frame)
333             return 0;
334         sibling = frame->tree().nextSibling();
335     }
336 
337     if (frame) {
338         ASSERT(!stayWithin || !sibling || sibling->tree().isDescendantOf(stayWithin));
339         return sibling;
340     }
341 
342     return 0;
343 }
344 
traverseNextWithWrap(bool wrap) const345 Frame* FrameTree::traverseNextWithWrap(bool wrap) const
346 {
347     if (Frame* result = traverseNext())
348         return result;
349 
350     if (wrap)
351         return m_thisFrame->page()->mainFrame();
352 
353     return 0;
354 }
355 
traversePreviousWithWrap(bool wrap) const356 Frame* FrameTree::traversePreviousWithWrap(bool wrap) const
357 {
358     // FIXME: besides the wrap feature, this is just the traversePreviousNode algorithm
359 
360     if (Frame* prevSibling = previousSibling())
361         return prevSibling->tree().deepLastChild();
362     if (Frame* parentFrame = parent())
363         return parentFrame;
364 
365     // no siblings, no parent, self==top
366     if (wrap)
367         return deepLastChild();
368 
369     // top view is always the last one in this ordering, so prev is nil without wrap
370     return 0;
371 }
372 
deepLastChild() const373 Frame* FrameTree::deepLastChild() const
374 {
375     Frame* result = m_thisFrame;
376     for (Frame* last = lastChild(); last; last = last->tree().lastChild())
377         result = last;
378 
379     return result;
380 }
381 
trace(Visitor * visitor)382 void FrameTree::trace(Visitor* visitor)
383 {
384     visitor->trace(m_thisFrame);
385 }
386 
387 } // namespace blink
388 
389 #ifndef NDEBUG
390 
printIndent(int indent)391 static void printIndent(int indent)
392 {
393     for (int i = 0; i < indent; ++i)
394         printf("    ");
395 }
396 
printFrames(const blink::Frame * frame,const blink::Frame * targetFrame,int indent)397 static void printFrames(const blink::Frame* frame, const blink::Frame* targetFrame, int indent)
398 {
399     if (frame == targetFrame) {
400         printf("--> ");
401         printIndent(indent - 1);
402     } else
403         printIndent(indent);
404 
405     blink::FrameView* view = frame->isLocalFrame() ? toLocalFrame(frame)->view() : 0;
406     printf("Frame %p %dx%d\n", frame, view ? view->width() : 0, view ? view->height() : 0);
407     printIndent(indent);
408     printf("  owner=%p\n", frame->owner());
409     printIndent(indent);
410     printf("  frameView=%p\n", view);
411     printIndent(indent);
412     printf("  document=%p\n", frame->isLocalFrame() ? toLocalFrame(frame)->document() : 0);
413     printIndent(indent);
414     printf("  uri=%s\n\n", frame->isLocalFrame() ? toLocalFrame(frame)->document()->url().string().utf8().data() : 0);
415 
416     for (blink::Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling())
417         printFrames(child, targetFrame, indent + 1);
418 }
419 
showFrameTree(const blink::Frame * frame)420 void showFrameTree(const blink::Frame* frame)
421 {
422     if (!frame) {
423         printf("Null input frame\n");
424         return;
425     }
426 
427     printFrames(frame->tree().top(), frame, 0);
428 }
429 
430 #endif
431