b836340c1507e8f161136262762bb1bf7636ba9e
[WebKit-https.git] / WebCore / khtml / xbl / xbl_binding_manager.cpp
1 #include "qptrdict.h"
2 #include "xml/dom_docimpl.h"
3 #include "xml/dom_elementimpl.h"
4 #include "rendering/render_style.h"
5 #include "xbl_binding_manager.h"
6 #include "xbl_binding.h"
7
8 using DOM::DocumentImpl;
9 using DOM::NodeImpl;
10 using DOM::ElementImpl;
11 using khtml::BindingURI;
12
13 namespace XBL {
14
15 XBLBindingManager::XBLBindingManager(DocumentImpl* doc)
16 :m_document(doc), m_bindingChainTable(0)
17 {
18 }
19
20 XBLBindingManager::~XBLBindingManager()
21 {
22     if (m_bindingChainTable) {
23         m_bindingChainTable->setAutoDelete(true);
24         delete m_bindingChainTable;
25     }
26 }
27
28 XBLBindingChain* XBLBindingManager::getBindingChain(NodeImpl* node)
29 {
30     if (!m_bindingChainTable)
31         return 0;
32     
33     return m_bindingChainTable->find(node);
34 }
35
36 void XBLBindingManager::setBindingChain(NodeImpl* node, XBLBindingChain* bindingChain)
37 {
38     if (!m_bindingChainTable)
39         m_bindingChainTable = new QPtrDict<XBLBindingChain>;
40     
41     if (bindingChain)
42         m_bindingChainTable->replace(node, bindingChain);
43     else
44         m_bindingChainTable->remove(node);
45 }
46
47 bool XBLBindingManager::loadBindings(NodeImpl* node, BindingURI* bindingURIs, 
48                                      bool isStyleBinding, bool* resolveStyle)
49 {
50     if (resolveStyle) *resolveStyle = false;
51     if (!node->isElementNode()) return true;
52     bool dirty = false;
53     XBLBindingChain* bindingChain = getBindingChain(node);
54     if (bindingChain && isStyleBinding) {
55         // Check to see if the binding is already installed.  If so, then we don't need
56         // to do anything.
57         XBLBindingChain* styleBindingChain = bindingChain->firstStyleBindingChain();
58         if (styleBindingChain) {
59             if (styleBindingChain->markedForDeath())
60                 return false; // The old bindings haven't destroyed themselves/fired their destructors yet.
61             
62             // See if the URIs match.
63             BindingURI* currURI = bindingURIs;
64             XBLBindingChain* currBindingChain = styleBindingChain;
65             for ( ; currURI && currBindingChain;
66                   currURI = currURI->next(), currBindingChain = currBindingChain->nextChain()) {
67                 if (currBindingChain->uri() != currURI->uri()) {
68                     styleBindingChain->markForDeath();
69                     return false;
70                 }
71             }
72             if ((currURI && !currBindingChain) || (currBindingChain && !currURI)) {
73                 styleBindingChain->markForDeath();
74                 return false;
75             }
76             
77             return bindingChain->loaded();
78         }
79     }
80
81     bindingChain = getBindingChain(node);
82     ElementImpl* elt = static_cast<ElementImpl*>(node);
83     for (BindingURI* currURI = bindingURIs; currURI; currURI = currURI->next()) {
84         XBLBindingChain* newBindingChain = new XBLBindingChain(elt, currURI->uri(), isStyleBinding);
85         if (newBindingChain) {
86             if (bindingChain && isStyleBinding)
87                 // Style bindings go on the end.  Regular bindings go on the front.
88                 bindingChain->lastBindingChain()->insertBindingChain(newBindingChain);
89             else {
90                 // Place on the front.
91                 newBindingChain->insertBindingChain(bindingChain);
92                 setBindingChain(node, newBindingChain); 
93             }
94             
95             dirty = true;
96         }
97         
98         bindingChain = newBindingChain;
99     }
100     
101     if (!bindingChain) return true; // We did nothing.
102     
103     // If the binding is completely loaded, then return true.  Otherwise return false.
104     bindingChain = getBindingChain(node);
105     bool loaded = bindingChain->loaded();
106     if (loaded && resolveStyle)
107         *resolveStyle = bindingChain->hasStylesheets();
108     return loaded;
109 }
110
111 void XBLBindingManager::checkLoadState(ElementImpl* elt)
112 {
113     XBLBindingChain* chain = getBindingChain(elt);
114     if (chain && chain->loaded())
115         elt->setChanged();
116 }
117
118 }