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 33namespace WebCore { 34 35// FIXME: Do we ever change tree scopes except between documents? 36void 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 (!node->isElementNode()) 64 continue; 65 66 if (node->hasSyntheticAttrChildNodes()) { 67 const Vector<RefPtr<Attr>>& attrs = toElement(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 83void 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 93static bool didMoveToNewDocumentWasCalled = false; 94static Document* oldDocumentDidMoveToNewDocumentWasCalledWith = 0; 95 96void TreeScopeAdopter::ensureDidMoveToNewDocumentWasCalled(Document* oldDocument) 97{ 98 ASSERT(!didMoveToNewDocumentWasCalled); 99 ASSERT_UNUSED(oldDocument, oldDocument == oldDocumentDidMoveToNewDocumentWasCalledWith); 100 didMoveToNewDocumentWasCalled = true; 101} 102#endif 103 104inline void TreeScopeAdopter::updateTreeScope(Node* node) const 105{ 106 ASSERT(!node->isTreeScope()); 107 ASSERT(&node->treeScope() == &m_oldScope); 108 node->setTreeScope(m_newScope); 109} 110 111inline 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 (node->isShadowRoot()) 128 toShadowRoot(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} 140