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/accessibility/AXObjectCache.h" 29 #include "core/dom/Attr.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 blink { 36 37 void TreeScopeAdopter::moveTreeToNewScope(Node& root) const 38 { 39 ASSERT(needsScopeChange()); 40 41 #if !ENABLE(OILPAN) 42 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 = oldScope().document(); 50 Document& newDocument = newScope().document(); 51 bool willMoveToNewDocument = oldDocument != newDocument; 52 AXObjectCache* axObjectCache = oldDocument.existingAXObjectCache(); 53 if (willMoveToNewDocument) 54 oldDocument.incDOMTreeVersion(); 55 56 for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) { 57 updateTreeScope(*node); 58 59 if (willMoveToNewDocument) { 60 if (axObjectCache) 61 axObjectCache->remove(node); 62 moveNodeToNewDocument(*node, oldDocument, newDocument); 63 } else if (node->hasRareData()) { 64 NodeRareData* rareData = node->rareData(); 65 if (rareData->nodeLists()) 66 rareData->nodeLists()->adoptTreeScope(); 67 } 68 69 if (!node->isElementNode()) 70 continue; 71 72 if (node->hasSyntheticAttrChildNodes()) { 73 WillBeHeapVector<RefPtrWillBeMember<Attr> >& attrs = *toElement(node)->attrNodeList(); 74 for (unsigned i = 0; i < attrs.size(); ++i) 75 moveTreeToNewScope(*attrs[i]); 76 } 77 78 for (ShadowRoot* shadow = node->youngestShadowRoot(); shadow; shadow = shadow->olderShadowRoot()) { 79 shadow->setParentTreeScope(newScope()); 80 if (willMoveToNewDocument) 81 moveTreeToNewDocument(*shadow, oldDocument, newDocument); 82 } 83 } 84 85 #if !ENABLE(OILPAN) 86 oldScope().guardDeref(); 87 #endif 88 } 89 90 void TreeScopeAdopter::moveTreeToNewDocument(Node& root, Document& oldDocument, Document& newDocument) const 91 { 92 ASSERT(oldDocument != newDocument); 93 for (Node* node = &root; node; node = NodeTraversal::next(*node, &root)) { 94 moveNodeToNewDocument(*node, oldDocument, newDocument); 95 96 if (node->hasSyntheticAttrChildNodes()) { 97 WillBeHeapVector<RefPtrWillBeMember<Attr> >& attrs = *toElement(node)->attrNodeList(); 98 for (unsigned i = 0; i < attrs.size(); ++i) 99 moveTreeToNewDocument(*attrs[i], oldDocument, newDocument); 100 } 101 102 for (ShadowRoot* shadow = node->youngestShadowRoot(); shadow; shadow = shadow->olderShadowRoot()) 103 moveTreeToNewDocument(*shadow, oldDocument, newDocument); 104 } 105 } 106 107 #if ENABLE(ASSERT) 108 static bool didMoveToNewDocumentWasCalled = false; 109 static Document* oldDocumentDidMoveToNewDocumentWasCalledWith = 0; 110 111 void TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(Document& oldDocument) 112 { 113 ASSERT(!didMoveToNewDocumentWasCalled); 114 ASSERT_UNUSED(oldDocument, oldDocument == oldDocumentDidMoveToNewDocumentWasCalledWith); 115 didMoveToNewDocumentWasCalled = true; 116 } 117 #endif 118 119 inline void TreeScopeAdopter::updateTreeScope(Node& node) const 120 { 121 ASSERT(!node.isTreeScope()); 122 ASSERT(node.treeScope() == oldScope()); 123 #if !ENABLE(OILPAN) 124 newScope().guardRef(); 125 oldScope().guardDeref(); 126 #endif 127 node.setTreeScope(m_newScope); 128 } 129 130 inline void TreeScopeAdopter::moveNodeToNewDocument(Node& node, Document& oldDocument, Document& newDocument) const 131 { 132 ASSERT(oldDocument != newDocument); 133 134 if (node.hasRareData()) { 135 NodeRareData* rareData = node.rareData(); 136 if (rareData->nodeLists()) 137 rareData->nodeLists()->adoptDocument(oldDocument, newDocument); 138 } 139 140 oldDocument.moveNodeIteratorsToNewDocument(node, newDocument); 141 142 if (node.isShadowRoot()) 143 toShadowRoot(node).setDocument(newDocument); 144 145 #if ENABLE(ASSERT) 146 didMoveToNewDocumentWasCalled = false; 147 oldDocumentDidMoveToNewDocumentWasCalledWith = &oldDocument; 148 #endif 149 150 node.didMoveToNewDocument(oldDocument); 151 ASSERT(didMoveToNewDocumentWasCalled); 152 } 153 154 } 155