1 /* 2 * Copyright (C) 2014 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/css/invalidation/DescendantInvalidationSet.h" 33 34 #include "core/css/resolver/StyleResolver.h" 35 #include "core/dom/Element.h" 36 37 namespace blink { 38 39 DescendantInvalidationSet::DescendantInvalidationSet() 40 : m_allDescendantsMightBeInvalid(false) 41 , m_customPseudoInvalid(false) 42 , m_treeBoundaryCrossing(false) 43 { 44 } 45 46 bool DescendantInvalidationSet::invalidatesElement(Element& element) const 47 { 48 if (m_allDescendantsMightBeInvalid) 49 return true; 50 51 if (m_tagNames && m_tagNames->contains(element.tagQName().localName())) 52 return true; 53 54 if (element.hasID() && m_ids && m_ids->contains(element.idForStyleResolution())) 55 return true; 56 57 if (element.hasClass() && m_classes) { 58 const SpaceSplitString& classNames = element.classNames(); 59 for (WillBeHeapHashSet<AtomicString>::const_iterator it = m_classes->begin(); it != m_classes->end(); ++it) { 60 if (classNames.contains(*it)) 61 return true; 62 } 63 } 64 65 if (element.hasAttributes() && m_attributes) { 66 for (WillBeHeapHashSet<AtomicString>::const_iterator it = m_attributes->begin(); it != m_attributes->end(); ++it) { 67 if (element.hasAttribute(*it)) 68 return true; 69 } 70 } 71 72 return false; 73 } 74 75 void DescendantInvalidationSet::combine(const DescendantInvalidationSet& other) 76 { 77 // No longer bother combining data structures, since the whole subtree is deemed invalid. 78 if (wholeSubtreeInvalid()) 79 return; 80 81 if (other.wholeSubtreeInvalid()) { 82 setWholeSubtreeInvalid(); 83 return; 84 } 85 86 if (other.customPseudoInvalid()) 87 setCustomPseudoInvalid(); 88 89 if (other.treeBoundaryCrossing()) 90 setTreeBoundaryCrossing(); 91 92 if (other.m_classes) { 93 WillBeHeapHashSet<AtomicString>::const_iterator end = other.m_classes->end(); 94 for (WillBeHeapHashSet<AtomicString>::const_iterator it = other.m_classes->begin(); it != end; ++it) 95 addClass(*it); 96 } 97 98 if (other.m_ids) { 99 WillBeHeapHashSet<AtomicString>::const_iterator end = other.m_ids->end(); 100 for (WillBeHeapHashSet<AtomicString>::const_iterator it = other.m_ids->begin(); it != end; ++it) 101 addId(*it); 102 } 103 104 if (other.m_tagNames) { 105 WillBeHeapHashSet<AtomicString>::const_iterator end = other.m_tagNames->end(); 106 for (WillBeHeapHashSet<AtomicString>::const_iterator it = other.m_tagNames->begin(); it != end; ++it) 107 addTagName(*it); 108 } 109 110 if (other.m_attributes) { 111 WillBeHeapHashSet<AtomicString>::const_iterator end = other.m_attributes->end(); 112 for (WillBeHeapHashSet<AtomicString>::const_iterator it = other.m_attributes->begin(); it != end; ++it) 113 addAttribute(*it); 114 } 115 } 116 117 WillBeHeapHashSet<AtomicString>& DescendantInvalidationSet::ensureClassSet() 118 { 119 if (!m_classes) 120 m_classes = adoptPtrWillBeNoop(new WillBeHeapHashSet<AtomicString>); 121 return *m_classes; 122 } 123 124 WillBeHeapHashSet<AtomicString>& DescendantInvalidationSet::ensureIdSet() 125 { 126 if (!m_ids) 127 m_ids = adoptPtrWillBeNoop(new WillBeHeapHashSet<AtomicString>); 128 return *m_ids; 129 } 130 131 WillBeHeapHashSet<AtomicString>& DescendantInvalidationSet::ensureTagNameSet() 132 { 133 if (!m_tagNames) 134 m_tagNames = adoptPtrWillBeNoop(new WillBeHeapHashSet<AtomicString>); 135 return *m_tagNames; 136 } 137 138 WillBeHeapHashSet<AtomicString>& DescendantInvalidationSet::ensureAttributeSet() 139 { 140 if (!m_attributes) 141 m_attributes = adoptPtrWillBeNoop(new WillBeHeapHashSet<AtomicString>); 142 return *m_attributes; 143 } 144 145 void DescendantInvalidationSet::addClass(const AtomicString& className) 146 { 147 if (wholeSubtreeInvalid()) 148 return; 149 ensureClassSet().add(className); 150 } 151 152 void DescendantInvalidationSet::addId(const AtomicString& id) 153 { 154 if (wholeSubtreeInvalid()) 155 return; 156 ensureIdSet().add(id); 157 } 158 159 void DescendantInvalidationSet::addTagName(const AtomicString& tagName) 160 { 161 if (wholeSubtreeInvalid()) 162 return; 163 ensureTagNameSet().add(tagName); 164 } 165 166 void DescendantInvalidationSet::addAttribute(const AtomicString& attribute) 167 { 168 if (wholeSubtreeInvalid()) 169 return; 170 ensureAttributeSet().add(attribute); 171 } 172 173 void DescendantInvalidationSet::setWholeSubtreeInvalid() 174 { 175 if (m_allDescendantsMightBeInvalid) 176 return; 177 178 m_allDescendantsMightBeInvalid = true; 179 m_treeBoundaryCrossing = false; 180 m_classes = nullptr; 181 m_ids = nullptr; 182 m_tagNames = nullptr; 183 m_attributes = nullptr; 184 } 185 186 void DescendantInvalidationSet::trace(Visitor* visitor) 187 { 188 #if ENABLE(OILPAN) 189 visitor->trace(m_classes); 190 visitor->trace(m_ids); 191 visitor->trace(m_tagNames); 192 visitor->trace(m_attributes); 193 #endif 194 } 195 196 #ifndef NDEBUG 197 void DescendantInvalidationSet::show() const 198 { 199 fprintf(stderr, "DescendantInvalidationSet { "); 200 if (m_allDescendantsMightBeInvalid) 201 fprintf(stderr, "* "); 202 if (m_customPseudoInvalid) 203 fprintf(stderr, "::custom "); 204 if (m_treeBoundaryCrossing) 205 fprintf(stderr, "::shadow/deep/ "); 206 if (m_ids) { 207 for (WillBeHeapHashSet<AtomicString>::const_iterator it = m_ids->begin(); it != m_ids->end(); ++it) 208 fprintf(stderr, "#%s ", (*it).ascii().data()); 209 } 210 if (m_classes) { 211 for (WillBeHeapHashSet<AtomicString>::const_iterator it = m_classes->begin(); it != m_classes->end(); ++it) 212 fprintf(stderr, ".%s ", (*it).ascii().data()); 213 } 214 if (m_tagNames) { 215 for (WillBeHeapHashSet<AtomicString>::const_iterator it = m_tagNames->begin(); it != m_tagNames->end(); ++it) 216 fprintf(stderr, "<%s> ", (*it).ascii().data()); 217 } 218 if (m_attributes) { 219 for (WillBeHeapHashSet<AtomicString>::const_iterator it = m_attributes->begin(); it != m_attributes->end(); ++it) 220 fprintf(stderr, "[%s] ", (*it).ascii().data()); 221 } 222 fprintf(stderr, "}\n"); 223 } 224 #endif // NDEBUG 225 226 } // namespace blink 227