Have is<>(T*) function do a null check on the pointer argument
[WebKit-https.git] / Source / WebCore / dom / TreeScopeAdopter.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
7  * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
8  * Copyright (C) 2011 Google Inc. All rights reserved.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "TreeScopeAdopter.h"
28
29 #include "Attr.h"
30 #include "ElementRareData.h"
31 #include "NodeTraversal.h"
32
33 namespace WebCore {
34
35 // FIXME: Do we ever change tree scopes except between documents?
36 void TreeScopeAdopter::moveTreeToNewScope(Node* root) const
37 {
38     ASSERT(needsScopeChange());
39
40     // If an element is moved from a document and then eventually back again the collection cache for
41     // that element may contain stale data as changes made to it will have updated the DOMTreeVersion
42     // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here
43     // we ensure that the collection cache will be invalidated as needed when the element is moved back.
44     Document& oldDocument = m_oldScope.documentScope();
45     Document& newDocument = m_newScope.documentScope();
46     bool willMoveToNewDocument = &oldDocument != &newDocument;
47     if (willMoveToNewDocument) {
48         oldDocument.incrementReferencingNodeCount();
49         oldDocument.incDOMTreeVersion();
50     }
51
52     for (Node* node = root; node; node = NodeTraversal::next(node, root)) {
53         updateTreeScope(node);
54
55         if (willMoveToNewDocument)
56             moveNodeToNewDocument(node, &oldDocument, &newDocument);
57         else if (node->hasRareData()) {
58             NodeRareData* rareData = node->rareData();
59             if (rareData->nodeLists())
60                 rareData->nodeLists()->adoptTreeScope();
61         }
62
63         if (!is<Element>(*node))
64             continue;
65
66         if (node->hasSyntheticAttrChildNodes()) {
67             const Vector<RefPtr<Attr>>& attrs = downcast<Element>(*node).attrNodeList();
68             for (unsigned i = 0; i < attrs.size(); ++i)
69                 moveTreeToNewScope(attrs[i].get());
70         }
71
72         if (ShadowRoot* shadow = node->shadowRoot()) {
73             shadow->setParentTreeScope(&m_newScope);
74             if (willMoveToNewDocument)
75                 moveShadowTreeToNewDocument(shadow, &oldDocument, &newDocument);
76         }
77     }
78
79     if (willMoveToNewDocument)
80         oldDocument.decrementReferencingNodeCount();
81 }
82
83 void TreeScopeAdopter::moveShadowTreeToNewDocument(ShadowRoot* shadowRoot, Document* oldDocument, Document* newDocument) const
84 {
85     for (Node* node = shadowRoot; node; node = NodeTraversal::next(node, shadowRoot)) {
86         moveNodeToNewDocument(node, oldDocument, newDocument);
87         if (ShadowRoot* shadow = node->shadowRoot())
88             moveShadowTreeToNewDocument(shadow, oldDocument, newDocument);
89     }
90 }
91
92 #ifndef NDEBUG
93 static bool didMoveToNewDocumentWasCalled = false;
94 static Document* oldDocumentDidMoveToNewDocumentWasCalledWith = 0;
95
96 void TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(Document* oldDocument)
97 {
98     ASSERT(!didMoveToNewDocumentWasCalled);
99     ASSERT_UNUSED(oldDocument, oldDocument == oldDocumentDidMoveToNewDocumentWasCalledWith);
100     didMoveToNewDocumentWasCalled = true;
101 }
102 #endif
103
104 inline void TreeScopeAdopter::updateTreeScope(Node* node) const
105 {
106     ASSERT(!node->isTreeScope());
107     ASSERT(&node->treeScope() == &m_oldScope);
108     node->setTreeScope(m_newScope);
109 }
110
111 inline void TreeScopeAdopter::moveNodeToNewDocument(Node* node, Document* oldDocument, Document* newDocument) const
112 {
113     ASSERT(!node->inDocument() || oldDocument != newDocument);
114
115     newDocument->incrementReferencingNodeCount();
116     oldDocument->decrementReferencingNodeCount();
117
118     if (node->hasRareData()) {
119         NodeRareData* rareData = node->rareData();
120         if (rareData->nodeLists())
121             rareData->nodeLists()->adoptDocument(oldDocument, newDocument);
122     }
123
124     if (oldDocument)
125         oldDocument->moveNodeIteratorsToNewDocument(node, newDocument);
126
127     if (is<ShadowRoot>(*node))
128         downcast<ShadowRoot>(*node).setDocumentScope(newDocument);
129
130 #ifndef NDEBUG
131     didMoveToNewDocumentWasCalled = false;
132     oldDocumentDidMoveToNewDocumentWasCalledWith = oldDocument;
133 #endif
134
135     node->didMoveToNewDocument(oldDocument);
136     ASSERT(didMoveToNewDocumentWasCalled);
137 }
138
139 }