1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) 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 #include "config.h" 26 #include "core/dom/TreeScopeAdopter.h" 27 28 #include "core/dom/Attr.h" 29 #include "core/dom/Document.h" 30 #include "core/dom/NodeRareData.h" 31 #include "core/dom/NodeTraversal.h" 32 #include "core/dom/shadow/ElementShadow.h" 33 #include "core/dom/shadow/ShadowRoot.h" 34 35 namespace WebCore { 36 37 void TreeScopeAdopter::moveTreeToNewScope(Node& root) const 38 { 39 ASSERT(needsScopeChange()); 40 41 #if !ENABLE(OILPAN) 42 m_oldScope.guardRef(); 43 #endif 44 45 // If an element is moved from a document and then eventually back again the collection cache for 46 // that element may contain stale data as changes made to it will have updated the DOMTreeVersion 47 // of the document it was moved to. By increasing the DOMTreeVersion of the donating document here 48 // we ensure that the collection cache will be invalidated as needed when the element is moved back. 49 Document& oldDocument = m_oldScope.document(); 50 Document& newDocument = m_newScope.document(); 51 bool willMoveToNewDocument = oldDocument != newDocument; 52 if (willMoveToNewDocument) 53 oldDocument.incDOMTreeVersion(); 54 55 for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) { 56 updateTreeScope(*node); 57 58 if (willMoveToNewDocument) 59 moveNodeToNewDocument(*node, oldDocument, newDocument); 60 else if (node->hasRareData()) { 61 NodeRareData* rareData = node->rareData(); 62 if (rareData->nodeLists()) 63 rareData->nodeLists()->adoptTreeScope(); 64 } 65 66 if (!node->isElementNode()) 67 continue; 68 69 if (node->hasSyntheticAttrChildNodes()) { 70 WillBeHeapVector<RefPtrWillBeMember<Attr> >& attrs = *toElement(node)->attrNodeList(); 71 for (unsigned i = 0; i < attrs.size(); ++i) 72 moveTreeToNewScope(*attrs[i]); 73 } 74 75 for (ShadowRoot* shadow = node->youngestShadowRoot(); shadow; shadow = shadow->olderShadowRoot()) { 76 shadow->setParentTreeScope(m_newScope); 77 if (willMoveToNewDocument) 78 moveTreeToNewDocument(*shadow, oldDocument, newDocument); 79 } 80 } 81 82 #if !ENABLE(OILPAN) 83 m_oldScope.guardDeref(); 84 #endif 85 } 86 87 void TreeScopeAdopter::moveTreeToNewDocument(Node& root, Document& oldDocument, Document& newDocument) const 88 { 89 ASSERT(oldDocument != newDocument); 90 for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) { 91 moveNodeToNewDocument(*node, oldDocument, newDocument); 92 for (ShadowRoot* shadow = node->youngestShadowRoot(); shadow; shadow = shadow->olderShadowRoot()) 93 moveTreeToNewDocument(*shadow, oldDocument, newDocument); 94 } 95 } 96 97 #ifndef NDEBUG 98 static bool didMoveToNewDocumentWasCalled = false; 99 static Document* oldDocumentDidMoveToNewDocumentWasCalledWith = 0; 100 101 void TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(Document& oldDocument) 102 { 103 ASSERT(!didMoveToNewDocumentWasCalled); 104 ASSERT_UNUSED(oldDocument, oldDocument == oldDocumentDidMoveToNewDocumentWasCalledWith); 105 didMoveToNewDocumentWasCalled = true; 106 } 107 #endif 108 109 inline void TreeScopeAdopter::updateTreeScope(Node& node) const 110 { 111 ASSERT(!node.isTreeScope()); 112 ASSERT(node.treeScope() == m_oldScope); 113 #if !ENABLE(OILPAN) 114 m_newScope.guardRef(); 115 m_oldScope.guardDeref(); 116 #endif 117 node.setTreeScope(&m_newScope); 118 } 119 120 inline void TreeScopeAdopter::moveNodeToNewDocument(Node& node, Document& oldDocument, Document& newDocument) const 121 { 122 ASSERT(oldDocument != newDocument); 123 124 if (node.hasRareData()) { 125 NodeRareData* rareData = node.rareData(); 126 if (rareData->nodeLists()) 127 rareData->nodeLists()->adoptDocument(oldDocument, newDocument); 128 } 129 130 oldDocument.moveNodeIteratorsToNewDocument(node, newDocument); 131 132 if (node.isShadowRoot()) 133 toShadowRoot(node).setDocument(newDocument); 134 135 #ifndef NDEBUG 136 didMoveToNewDocumentWasCalled = false; 137 oldDocumentDidMoveToNewDocumentWasCalledWith = &oldDocument; 138 #endif 139 140 node.didMoveToNewDocument(oldDocument); 141 ASSERT(didMoveToNewDocumentWasCalled); 142 } 143 144 } 145