File indexing completed on 2024-04-28 11:39:36
0001 /* 0002 * This file is part of the DOM implementation for KDE. 0003 * 0004 * Copyright (C) 2006 Allan Sandfeld Jensen (kde@carewolf.com) 0005 * (C) 2009 Vyacheslav Tokarev (tsjoker@gmail.com) 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public License 0018 * along with this library; see the file COPYING.LIB. If not, write to 0019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 * 0022 */ 0023 0024 #ifndef _DOM_restyler_h_ 0025 #define _DOM_restyler_h_ 0026 0027 #include <bitset> 0028 #include <wtf/HashMap.h> 0029 #include <wtf/HashSet.h> 0030 #include "xml/dom_elementimpl.h" 0031 #include <QVarLengthArray> 0032 0033 /*namespace DOM { 0034 class ElementImpl; 0035 }*/ 0036 0037 // Restyle dependency tracker for dynamic DOM 0038 0039 namespace khtml 0040 { 0041 0042 using DOM::ElementImpl; 0043 0044 // These types are different types of dependencies, and serves to identify which element should be 0045 // restyled when a change of that kind triggers on the element 0046 enum StructuralDependencyType { 0047 // Style relies on the children of the element (unaffected by append & close) 0048 StructuralDependency = 0, 0049 // Style relies on the last children of the element (affected by append & close) 0050 BackwardsStructuralDependency = 1, 0051 // Style relies on the element having hover 0052 HoverDependency = 2, 0053 // Style relies on the element being active 0054 ActiveDependency = 3, 0055 // Style relies on another state of element (focus, disabled, checked, etc.) 0056 // (focus is special cased though since elements always depend on their own focus) 0057 OtherStateDependency = 4, 0058 LastStructuralDependency 0059 }; 0060 0061 // Attribute dependencies are much coarser than structural, for memory reasons rather than performance 0062 // This tracks global dependencies of various kinds. 0063 // The groups are separated into where possible depending elements might be: 0064 enum AttributeDependencyType { 0065 // Style of the changed element depend on this attribute 0066 PersonalDependency = 0, 0067 // Style of the elements children depend on this attribute 0068 AncestorDependency = 1, 0069 // Style of the elements later siblings or their children depend on this attribute 0070 PredecessorDependency = 2, 0071 LastAttributeDependency 0072 }; 0073 0074 // MultiMap implementation by mapping: ElementImpl* -> HashSet of ElementImpl* 0075 // it includes an optimization which covers common mapping case: element -> element, element -> parent 0076 // and set is created only if it contains more than one element otherwise direct mapping is stored as is 0077 struct ElementMap { 0078 private: 0079 typedef WTF::HashSet<ElementImpl *> HashSet; 0080 struct Value { 0081 union { 0082 HashSet *set; 0083 ElementImpl *element; 0084 } m_value; 0085 bool isSet : 1; 0086 bool parentDependency : 1; 0087 bool selfDependency : 1; 0088 }; 0089 typedef WTF::HashMap<ElementImpl *, Value> HashMap; 0090 typedef HashMap::iterator Iterator; 0091 HashMap map; 0092 0093 void removeIfEmpty(const Iterator &it) 0094 { 0095 Value &value = it->second; 0096 if (value.isSet && value.m_value.set->isEmpty()) { 0097 delete value.m_value.set; 0098 value.isSet = false; 0099 value.m_value.element = nullptr; 0100 } 0101 if (!value.isSet && !value.m_value.element && !value.parentDependency && !value.selfDependency) { 0102 map.remove(it); 0103 } 0104 } 0105 0106 public: 0107 typedef QVarLengthArray<ElementImpl *> ElementsList; 0108 0109 ~ElementMap() 0110 { 0111 Iterator end = map.end(); 0112 for (Iterator it = map.begin(); it != end; ++it) 0113 if (it->second.isSet) { 0114 delete it->second.m_value.set; 0115 } 0116 } 0117 0118 void add(ElementImpl *a, ElementImpl *b) 0119 { 0120 std::pair<Iterator, bool> it = map.add(a, Value()); 0121 Value &value = it.first->second; 0122 if (it.second) { 0123 value.isSet = false; 0124 value.parentDependency = false; 0125 value.selfDependency = false; 0126 value.m_value.element = nullptr; 0127 } 0128 if (b == a) { 0129 value.selfDependency = true; 0130 } else if (b == a->parentNode()) { 0131 value.parentDependency = true; 0132 } else if (value.isSet) { 0133 value.m_value.set->add(b); 0134 } else if (!value.m_value.element || value.m_value.element == b) { 0135 value.m_value.element = b; 0136 } else { 0137 // convert into set 0138 HashSet *temp = new HashSet(); 0139 temp->add(value.m_value.element); 0140 temp->add(b); 0141 value.m_value.set = temp; 0142 value.isSet = true; 0143 } 0144 } 0145 0146 void remove(ElementImpl *a, ElementImpl *b) 0147 { 0148 Iterator it = map.find(a); 0149 if (it == map.end()) { 0150 return; 0151 } 0152 Value &value = it->second; 0153 if (b == a) { 0154 value.selfDependency = false; 0155 } else if (b == a->parentNode()) { 0156 value.parentDependency = false; 0157 } else if (value.isSet) { 0158 // don't care if set contains 1 element after this operation 0159 // it could be converted back into non-set storage but it's a minor optimization only 0160 value.m_value.set->remove(b); 0161 } else if (value.m_value.element == b) { 0162 value.m_value.element = nullptr; 0163 } 0164 removeIfEmpty(it); 0165 } 0166 0167 void remove(ElementImpl *a) 0168 { 0169 Iterator it = map.find(a); 0170 if (it != map.end()) { 0171 if (it->second.isSet) { 0172 delete it->second.m_value.set; 0173 } 0174 map.remove(it); 0175 } 0176 } 0177 0178 private: 0179 void addFromSet(HashSet *set, ElementsList &array) 0180 { 0181 HashSet::iterator end = set->end(); 0182 for (HashSet::iterator it = set->begin(); it != end; ++it) { 0183 array.append(*it); 0184 } 0185 } 0186 0187 public: 0188 void getElements(ElementImpl *element, ElementsList &array) 0189 { 0190 Iterator it = map.find(element); 0191 if (it == map.end()) { 0192 return; 0193 } 0194 Value &value = it->second; 0195 if (value.parentDependency) { 0196 array.append(static_cast<ElementImpl *>(element->parentNode())); 0197 } 0198 if (value.selfDependency) { 0199 array.append(element); 0200 } 0201 if (value.isSet) { 0202 addFromSet(value.m_value.set, array); 0203 } 0204 if (!value.isSet && value.m_value.element) { 0205 array.append(value.m_value.element); 0206 } 0207 } 0208 }; 0209 0210 /** 0211 * @internal 0212 */ 0213 class DynamicDomRestyler 0214 { 0215 public: 0216 DynamicDomRestyler(); 0217 0218 // Structural dependencies are tracked from element to subject 0219 void addDependency(ElementImpl *subject, ElementImpl *dependency, StructuralDependencyType type); 0220 void resetDependencies(ElementImpl *subject); 0221 void restyleDependent(ElementImpl *dependency, StructuralDependencyType type); 0222 0223 // Attribute dependencies are traced on attribute alone 0224 void addDependency(uint attrID, AttributeDependencyType type); 0225 bool checkDependency(uint attrID, AttributeDependencyType type); 0226 0227 void dumpStats() const; 0228 private: 0229 // Map of dependencies. 0230 ElementMap dependency_map[LastStructuralDependency]; 0231 // Map of reverse dependencies. For fast reset 0232 ElementMap reverse_map; 0233 0234 // Map of the various attribute dependencies 0235 std::bitset<512> attribute_map[LastAttributeDependency]; 0236 }; 0237 0238 } 0239 0240 #endif 0241