• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 WebCore {
14 
15 #ifndef NDEBUG
16 static unsigned checkConnectedSubframeCountIsConsistent(Node&);
17 #endif
18 
disconnect(DisconnectPolicy policy)19 void ChildFrameDisconnector::disconnect(DisconnectPolicy policy)
20 {
21 #ifndef NDEBUG
22     checkConnectedSubframeCountIsConsistent(m_root);
23 #endif
24 
25     if (!m_root.connectedSubframeCount())
26         return;
27 
28     if (policy == RootAndDescendants) {
29         collectFrameOwners(m_root);
30     } else {
31         for (Node* child = m_root.firstChild(); child; child = child->nextSibling())
32             collectFrameOwners(*child);
33     }
34 
35     disconnectCollectedFrameOwners();
36 }
37 
collectFrameOwners(Node & root)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 
disconnectCollectedFrameOwners()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(m_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 || m_root.containsIncludingShadowDOM(owner))
65             owner->disconnectContentFrame();
66     }
67 }
68 
collectFrameOwners(ElementShadow & shadow)69 void ChildFrameDisconnector::collectFrameOwners(ElementShadow& shadow)
70 {
71     for (ShadowRoot* root = shadow.youngestShadowRoot(); root; root = root->olderShadowRoot())
72         collectFrameOwners(*root);
73 }
74 
75 #ifndef NDEBUG
checkConnectedSubframeCountIsConsistent(Node & node)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 }
107