Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / ChildFrameDisconnector.cpp
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 "core/dom/ChildFrameDisconnector.h"
7
8 #include "core/dom/shadow/ElementShadow.h"
9 #include "core/dom/shadow/ShadowRoot.h"
10 #include "core/html/HTMLFrameOwnerElement.h"
11 #include "wtf/Assertions.h"
12
13 namespace blink {
14
15 #if ENABLE(ASSERT)
16 static unsigned checkConnectedSubframeCountIsConsistent(Node&);
17 #endif
18
19 void ChildFrameDisconnector::disconnect(DisconnectPolicy policy)
20 {
21 #if ENABLE(ASSERT)
22     checkConnectedSubframeCountIsConsistent(root());
23 #endif
24
25     if (!root().connectedSubframeCount())
26         return;
27
28     if (policy == RootAndDescendants) {
29         collectFrameOwners(root());
30     } else {
31         for (Node* child = root().firstChild(); child; child = child->nextSibling())
32             collectFrameOwners(*child);
33     }
34
35     disconnectCollectedFrameOwners();
36 }
37
38 void ChildFrameDisconnector::collectFrameOwners(Node& root)
39 {
40     if (!root.connectedSubframeCount())
41         return;
42
43     if (root.isHTMLElement() && root.isFrameOwnerElement())
44         m_frameOwners.append(&toHTMLFrameOwnerElement(root));
45
46     for (Node* child = root.firstChild(); child; child = child->nextSibling())
47         collectFrameOwners(*child);
48
49     ElementShadow* shadow = root.isElementNode() ? toElement(root).shadow() : 0;
50     if (shadow)
51         collectFrameOwners(*shadow);
52 }
53
54 void ChildFrameDisconnector::disconnectCollectedFrameOwners()
55 {
56     // Must disable frame loading in the subtree so an unload handler cannot
57     // insert more frames and create loaded frames in detached subtrees.
58     SubframeLoadingDisabler disabler(root());
59
60     for (unsigned i = 0; i < m_frameOwners.size(); ++i) {
61         HTMLFrameOwnerElement* owner = m_frameOwners[i].get();
62         // Don't need to traverse up the tree for the first owner since no
63         // script could have moved it.
64         if (!i || root().containsIncludingShadowDOM(owner))
65             owner->disconnectContentFrame();
66     }
67 }
68
69 void ChildFrameDisconnector::collectFrameOwners(ElementShadow& shadow)
70 {
71     for (ShadowRoot* root = shadow.youngestShadowRoot(); root; root = root->olderShadowRoot())
72         collectFrameOwners(*root);
73 }
74
75 #if ENABLE(ASSERT)
76 static unsigned checkConnectedSubframeCountIsConsistent(Node& node)
77 {
78     unsigned count = 0;
79
80     if (node.isElementNode()) {
81         if (node.isFrameOwnerElement() && toHTMLFrameOwnerElement(node).contentFrame())
82             count++;
83
84         if (ElementShadow* shadow = toElement(node).shadow()) {
85             for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot())
86                 count += checkConnectedSubframeCountIsConsistent(*root);
87         }
88     }
89
90     for (Node* child = node.firstChild(); child; child = child->nextSibling())
91         count += checkConnectedSubframeCountIsConsistent(*child);
92
93     // If we undercount there's possibly a security bug since we'd leave frames
94     // in subtrees outside the document.
95     ASSERT(node.connectedSubframeCount() >= count);
96
97     // If we overcount it's safe, but not optimal because it means we'll traverse
98     // through the document in ChildFrameDisconnector looking for frames that have
99     // already been disconnected.
100     ASSERT(node.connectedSubframeCount() == count);
101
102     return count;
103 }
104 #endif
105
106 }