1 /* 2 * Copyright (C) 2011 Google Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "TreeScope.h" 28 29 #include "Element.h" 30 #include "HTMLAnchorElement.h" 31 #include "HTMLMapElement.h" 32 #include "HTMLNames.h" 33 #include "NodeRareData.h" 34 35 namespace WebCore { 36 37 using namespace HTMLNames; 38 39 TreeScope::TreeScope(Document* document, ConstructionType constructionType) 40 : ContainerNode(0, constructionType) 41 , m_parentTreeScope(0) 42 , m_accessKeyMapValid(false) 43 , m_numNodeListCaches(0) 44 { 45 m_document = document; 46 if (document != this) { 47 // Assume document as parent scope 48 m_parentTreeScope = document; 49 // FIXME: This branch should be inert until shadow scopes are landed. 50 ASSERT_NOT_REACHED(); 51 } 52 } 53 54 TreeScope::~TreeScope() 55 { 56 if (hasRareData()) 57 rareData()->setTreeScope(0); 58 } 59 60 void TreeScope::destroyTreeScopeData() 61 { 62 m_elementsById.clear(); 63 m_imageMapsByName.clear(); 64 m_elementsByAccessKey.clear(); 65 } 66 67 void TreeScope::setParentTreeScope(TreeScope* newParentScope) 68 { 69 // A document node cannot be re-parented. 70 ASSERT(!isDocumentNode()); 71 // Every scope other than document needs a parent scope. 72 ASSERT(m_parentTreeScope); 73 ASSERT(newParentScope); 74 75 m_parentTreeScope = newParentScope; 76 } 77 78 Element* TreeScope::getElementById(const AtomicString& elementId) const 79 { 80 if (elementId.isEmpty()) 81 return 0; 82 return m_elementsById.getElementById(elementId.impl(), this); 83 } 84 85 void TreeScope::addElementById(const AtomicString& elementId, Element* element) 86 { 87 m_elementsById.add(elementId.impl(), element); 88 } 89 90 void TreeScope::removeElementById(const AtomicString& elementId, Element* element) 91 { 92 m_elementsById.remove(elementId.impl(), element); 93 } 94 95 Element* TreeScope::getElementByAccessKey(const String& key) const 96 { 97 if (key.isEmpty()) 98 return 0; 99 if (!m_accessKeyMapValid) { 100 for (Node* n = firstChild(); n; n = n->traverseNextNode()) { 101 if (!n->isElementNode()) 102 continue; 103 Element* element = static_cast<Element*>(n); 104 const AtomicString& accessKey = element->getAttribute(accesskeyAttr); 105 if (!accessKey.isEmpty()) 106 m_elementsByAccessKey.set(accessKey.impl(), element); 107 } 108 m_accessKeyMapValid = true; 109 } 110 return m_elementsByAccessKey.get(key.impl()); 111 } 112 113 void TreeScope::invalidateAccessKeyMap() 114 { 115 m_accessKeyMapValid = false; 116 m_elementsByAccessKey.clear(); 117 } 118 119 void TreeScope::addImageMap(HTMLMapElement* imageMap) 120 { 121 AtomicStringImpl* name = imageMap->getName().impl(); 122 if (!name) 123 return; 124 m_imageMapsByName.add(name, imageMap); 125 } 126 127 void TreeScope::removeImageMap(HTMLMapElement* imageMap) 128 { 129 AtomicStringImpl* name = imageMap->getName().impl(); 130 if (!name) 131 return; 132 m_imageMapsByName.remove(name, imageMap); 133 } 134 135 HTMLMapElement* TreeScope::getImageMap(const String& url) const 136 { 137 if (url.isNull()) 138 return 0; 139 size_t hashPos = url.find('#'); 140 String name = (hashPos == notFound ? url : url.substring(hashPos + 1)).impl(); 141 if (document()->isHTMLDocument()) 142 return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByLowercasedMapName(AtomicString(name.lower()).impl(), this)); 143 return static_cast<HTMLMapElement*>(m_imageMapsByName.getElementByMapName(AtomicString(name).impl(), this)); 144 } 145 146 Element* TreeScope::findAnchor(const String& name) 147 { 148 if (name.isEmpty()) 149 return 0; 150 if (Element* element = getElementById(name)) 151 return element; 152 for (Node* node = this; node; node = node->traverseNextNode()) { 153 if (node->hasTagName(aTag)) { 154 HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node); 155 if (document()->inQuirksMode()) { 156 // Quirks mode, case insensitive comparison of names. 157 if (equalIgnoringCase(anchor->name(), name)) 158 return anchor; 159 } else { 160 // Strict mode, names need to match exactly. 161 if (anchor->name() == name) 162 return anchor; 163 } 164 } 165 } 166 return 0; 167 } 168 169 } // namespace WebCore 170 171