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