Home | History | Annotate | Download | only in page
      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/Frame.h"
     26 #include "core/frame/FrameView.h"
     27 #include "core/page/Page.h"
     28 #include "core/page/PageGroup.h"
     29 #include "wtf/Vector.h"
     30 #include "wtf/text/CString.h"
     31 #include "wtf/text/StringBuilder.h"
     32 
     33 using std::swap;
     34 
     35 namespace WebCore {
     36 
     37 FrameTree::~FrameTree()
     38 {
     39     for (Frame* child = firstChild(); child; child = child->tree().nextSibling())
     40         child->setView(0);
     41 }
     42 
     43 void FrameTree::setName(const AtomicString& name)
     44 {
     45     m_name = name;
     46     if (!parent()) {
     47         m_uniqueName = name;
     48         return;
     49     }
     50     m_uniqueName = AtomicString(); // Remove our old frame name so it's not considered in uniqueChildName.
     51     m_uniqueName = parent()->tree().uniqueChildName(name);
     52 }
     53 
     54 Frame* FrameTree::parent() const
     55 {
     56     return m_parent;
     57 }
     58 
     59 void FrameTree::appendChild(PassRefPtr<Frame> child)
     60 {
     61     ASSERT(child->page() == m_thisFrame->page());
     62     child->tree().m_parent = m_thisFrame;
     63     Frame* oldLast = m_lastChild;
     64     m_lastChild = child.get();
     65 
     66     if (oldLast) {
     67         child->tree().m_previousSibling = oldLast;
     68         oldLast->tree().m_nextSibling = child;
     69     } else
     70         m_firstChild = child;
     71 
     72     m_scopedChildCount = invalidCount;
     73 
     74     ASSERT(!m_lastChild->tree().m_nextSibling);
     75 }
     76 
     77 void FrameTree::removeChild(Frame* child)
     78 {
     79     child->tree().m_parent = 0;
     80 
     81     // Slightly tricky way to prevent deleting the child until we are done with it, w/o
     82     // extra refs. These swaps leave the child in a circular list by itself. Clearing its
     83     // previous and next will then finally deref it.
     84 
     85     RefPtr<Frame>& newLocationForNext = m_firstChild == child ? m_firstChild : child->tree().m_previousSibling->tree().m_nextSibling;
     86     Frame*& newLocationForPrevious = m_lastChild == child ? m_lastChild : child->tree().m_nextSibling->tree().m_previousSibling;
     87     swap(newLocationForNext, child->tree().m_nextSibling);
     88     // For some inexplicable reason, the following line does not compile without the explicit std:: namespace
     89     std::swap(newLocationForPrevious, child->tree().m_previousSibling);
     90 
     91     child->tree().m_previousSibling = 0;
     92     child->tree().m_nextSibling = 0;
     93 
     94     m_scopedChildCount = invalidCount;
     95 }
     96 
     97 AtomicString FrameTree::uniqueChildName(const AtomicString& requestedName) const
     98 {
     99     if (!requestedName.isEmpty() && !child(requestedName) && requestedName != "_blank")
    100         return requestedName;
    101 
    102     // Create a repeatable name for a child about to be added to us. The name must be
    103     // unique within the frame tree. The string we generate includes a "path" of names
    104     // from the root frame down to us. For this path to be unique, each set of siblings must
    105     // contribute a unique name to the path, which can't collide with any HTML-assigned names.
    106     // We generate this path component by index in the child list along with an unlikely
    107     // frame name that can't be set in HTML because it collides with comment syntax.
    108 
    109     const char framePathPrefix[] = "<!--framePath ";
    110     const int framePathPrefixLength = 14;
    111     const int framePathSuffixLength = 3;
    112 
    113     // Find the nearest parent that has a frame with a path in it.
    114     Vector<Frame*, 16> chain;
    115     Frame* frame;
    116     for (frame = m_thisFrame; frame; frame = frame->tree().parent()) {
    117         if (frame->tree().uniqueName().startsWith(framePathPrefix))
    118             break;
    119         chain.append(frame);
    120     }
    121     StringBuilder name;
    122     name.append(framePathPrefix);
    123     if (frame) {
    124         name.append(frame->tree().uniqueName().string().substring(framePathPrefixLength,
    125             frame->tree().uniqueName().length() - framePathPrefixLength - framePathSuffixLength));
    126     }
    127     for (int i = chain.size() - 1; i >= 0; --i) {
    128         frame = chain[i];
    129         name.append('/');
    130         name.append(frame->tree().uniqueName());
    131     }
    132 
    133     name.appendLiteral("/<!--frame");
    134     name.appendNumber(childCount());
    135     name.appendLiteral("-->-->");
    136 
    137     return name.toAtomicString();
    138 }
    139 
    140 Frame* FrameTree::scopedChild(unsigned index) const
    141 {
    142     TreeScope* scope = m_thisFrame->document();
    143     if (!scope)
    144         return 0;
    145 
    146     unsigned scopedIndex = 0;
    147     for (Frame* result = firstChild(); result; result = result->tree().nextSibling()) {
    148         if (result->inScope(scope)) {
    149             if (scopedIndex == index)
    150                 return result;
    151             scopedIndex++;
    152         }
    153     }
    154 
    155     return 0;
    156 }
    157 
    158 Frame* FrameTree::scopedChild(const AtomicString& name) const
    159 {
    160     TreeScope* scope = m_thisFrame->document();
    161     if (!scope)
    162         return 0;
    163 
    164     for (Frame* child = firstChild(); child; child = child->tree().nextSibling())
    165         if (child->tree().uniqueName() == name && child->inScope(scope))
    166             return child;
    167     return 0;
    168 }
    169 
    170 inline unsigned FrameTree::scopedChildCount(TreeScope* scope) const
    171 {
    172     if (!scope)
    173         return 0;
    174 
    175     unsigned scopedCount = 0;
    176     for (Frame* result = firstChild(); result; result = result->tree().nextSibling()) {
    177         if (result->inScope(scope))
    178             scopedCount++;
    179     }
    180 
    181     return scopedCount;
    182 }
    183 
    184 unsigned FrameTree::scopedChildCount() const
    185 {
    186     if (m_scopedChildCount == invalidCount)
    187         m_scopedChildCount = scopedChildCount(m_thisFrame->document());
    188     return m_scopedChildCount;
    189 }
    190 
    191 unsigned FrameTree::childCount() const
    192 {
    193     unsigned count = 0;
    194     for (Frame* result = firstChild(); result; result = result->tree().nextSibling())
    195         ++count;
    196     return count;
    197 }
    198 
    199 Frame* FrameTree::child(const AtomicString& name) const
    200 {
    201     for (Frame* child = firstChild(); child; child = child->tree().nextSibling())
    202         if (child->tree().uniqueName() == name)
    203             return child;
    204     return 0;
    205 }
    206 
    207 Frame* FrameTree::find(const AtomicString& name) const
    208 {
    209     if (name == "_self" || name == "_current" || name.isEmpty())
    210         return m_thisFrame;
    211 
    212     if (name == "_top")
    213         return top();
    214 
    215     if (name == "_parent")
    216         return parent() ? parent() : m_thisFrame;
    217 
    218     // Since "_blank" should never be any frame's name, the following just amounts to an optimization.
    219     if (name == "_blank")
    220         return 0;
    221 
    222     // Search subtree starting with this frame first.
    223     for (Frame* frame = m_thisFrame; frame; frame = frame->tree().traverseNext(m_thisFrame))
    224         if (frame->tree().uniqueName() == name)
    225             return frame;
    226 
    227     // Search the entire tree for this page next.
    228     Page* page = m_thisFrame->page();
    229 
    230     // The frame could have been detached from the page, so check it.
    231     if (!page)
    232         return 0;
    233 
    234     for (Frame* frame = page->mainFrame(); frame; frame = frame->tree().traverseNext())
    235         if (frame->tree().uniqueName() == name)
    236             return frame;
    237 
    238     // Search the entire tree of each of the other pages in this namespace.
    239     // FIXME: Is random order OK?
    240     const HashSet<Page*>& pages = page->group().pages();
    241     HashSet<Page*>::const_iterator end = pages.end();
    242     for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
    243         Page* otherPage = *it;
    244         if (otherPage != page) {
    245             for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree().traverseNext()) {
    246                 if (frame->tree().uniqueName() == name)
    247                     return frame;
    248             }
    249         }
    250     }
    251 
    252     return 0;
    253 }
    254 
    255 bool FrameTree::isDescendantOf(const Frame* ancestor) const
    256 {
    257     if (!ancestor)
    258         return false;
    259 
    260     if (m_thisFrame->page() != ancestor->page())
    261         return false;
    262 
    263     for (Frame* frame = m_thisFrame; frame; frame = frame->tree().parent())
    264         if (frame == ancestor)
    265             return true;
    266     return false;
    267 }
    268 
    269 Frame* FrameTree::traverseNext(const Frame* stayWithin) const
    270 {
    271     Frame* child = firstChild();
    272     if (child) {
    273         ASSERT(!stayWithin || child->tree().isDescendantOf(stayWithin));
    274         return child;
    275     }
    276 
    277     if (m_thisFrame == stayWithin)
    278         return 0;
    279 
    280     Frame* sibling = nextSibling();
    281     if (sibling) {
    282         ASSERT(!stayWithin || sibling->tree().isDescendantOf(stayWithin));
    283         return sibling;
    284     }
    285 
    286     Frame* frame = m_thisFrame;
    287     while (!sibling && (!stayWithin || frame->tree().parent() != stayWithin)) {
    288         frame = frame->tree().parent();
    289         if (!frame)
    290             return 0;
    291         sibling = frame->tree().nextSibling();
    292     }
    293 
    294     if (frame) {
    295         ASSERT(!stayWithin || !sibling || sibling->tree().isDescendantOf(stayWithin));
    296         return sibling;
    297     }
    298 
    299     return 0;
    300 }
    301 
    302 Frame* FrameTree::traverseNextWithWrap(bool wrap) const
    303 {
    304     if (Frame* result = traverseNext())
    305         return result;
    306 
    307     if (wrap)
    308         return m_thisFrame->page()->mainFrame();
    309 
    310     return 0;
    311 }
    312 
    313 Frame* FrameTree::traversePreviousWithWrap(bool wrap) const
    314 {
    315     // FIXME: besides the wrap feature, this is just the traversePreviousNode algorithm
    316 
    317     if (Frame* prevSibling = previousSibling())
    318         return prevSibling->tree().deepLastChild();
    319     if (Frame* parentFrame = parent())
    320         return parentFrame;
    321 
    322     // no siblings, no parent, self==top
    323     if (wrap)
    324         return deepLastChild();
    325 
    326     // top view is always the last one in this ordering, so prev is nil without wrap
    327     return 0;
    328 }
    329 
    330 Frame* FrameTree::deepLastChild() const
    331 {
    332     Frame* result = m_thisFrame;
    333     for (Frame* last = lastChild(); last; last = last->tree().lastChild())
    334         result = last;
    335 
    336     return result;
    337 }
    338 
    339 Frame* FrameTree::top() const
    340 {
    341     Frame* frame = m_thisFrame;
    342     for (Frame* parent = m_thisFrame; parent; parent = parent->tree().parent())
    343         frame = parent;
    344     return frame;
    345 }
    346 
    347 } // namespace WebCore
    348 
    349 #ifndef NDEBUG
    350 
    351 static void printIndent(int indent)
    352 {
    353     for (int i = 0; i < indent; ++i)
    354         printf("    ");
    355 }
    356 
    357 static void printFrames(const WebCore::Frame* frame, const WebCore::Frame* targetFrame, int indent)
    358 {
    359     if (frame == targetFrame) {
    360         printf("--> ");
    361         printIndent(indent - 1);
    362     } else
    363         printIndent(indent);
    364 
    365     WebCore::FrameView* view = frame->view();
    366     printf("Frame %p %dx%d\n", frame, view ? view->width() : 0, view ? view->height() : 0);
    367     printIndent(indent);
    368     printf("  ownerElement=%p\n", frame->ownerElement());
    369     printIndent(indent);
    370     printf("  frameView=%p\n", view);
    371     printIndent(indent);
    372     printf("  document=%p\n", frame->document());
    373     printIndent(indent);
    374     printf("  uri=%s\n\n", frame->document()->documentURI().utf8().data());
    375 
    376     for (WebCore::Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling())
    377         printFrames(child, targetFrame, indent + 1);
    378 }
    379 
    380 void showFrameTree(const WebCore::Frame* frame)
    381 {
    382     if (!frame) {
    383         printf("Null input frame\n");
    384         return;
    385     }
    386 
    387     printFrames(frame->tree().top(), frame, 0);
    388 }
    389 
    390 #endif
    391