Disable XBL. The loadBindings call was taking 0.1-0.25%. While I know how to get...
[WebKit-https.git] / WebCore / khtml / xbl / xbl_tokenizer.cpp
1 #ifndef KHTML_NO_XBL
2
3 #include "dom/dom_node.h"
4 #include "xml/dom_elementimpl.h"
5 #include "misc/htmlattrs.h"
6
7 #include "xbl_tokenizer.h"
8 #include "xbl_docimpl.h"
9 #include "xbl_protobinding.h"
10 #include "xbl_protohandler.h"
11 #include "xbl_protoimplementation.h"
12
13 using DOM::DocumentPtr;
14 using DOM::ElementImpl;
15 using DOM::Node;
16
17 namespace XBL {
18
19 const char xblNS[] = "http://www.mozilla.org/xbl";
20     
21 XBLTokenHandler::XBLTokenHandler(DocumentPtr* doc)
22 :   XMLHandler(doc, 0),
23     m_state(eXBL_InDocument),
24     m_secondaryState(eXBL_None),
25     m_binding(0),
26     m_handler(0),
27     m_implementation(0),
28     m_member(0),
29     m_property(0),
30     m_method(0),
31     m_field(0)
32 {
33 }
34
35 XBLTokenHandler::~XBLTokenHandler()
36 {
37 }
38
39 XBLDocumentImpl* XBLTokenHandler::xblDocument() const
40 {
41     return static_cast<XBLDocumentImpl*>(m_doc->document());
42 }
43
44 bool XBLTokenHandler::startElement(const QString& namespaceURI, const QString& localName, const QString& qName, 
45                                    const QXmlAttributes& attrs)
46 {
47     if (namespaceURI == xblNS) {
48         if (localName == "binding")
49             m_state = eXBL_InBinding;
50         else if (localName == "content")
51             m_state = eXBL_InContent;
52         else if (localName == "handlers") {
53             m_state = eXBL_InHandlers;
54             return true;
55         }
56         else if (localName == "handler") {
57             m_secondaryState = eXBL_InHandler;
58             createHandler(attrs);
59             return true;
60         }
61         else if (localName == "resources") {
62             m_state = eXBL_InResources;
63             return true;
64         }
65         else if (m_state == eXBL_InResources) {
66             if (localName == "stylesheet" || localName == "image")
67                 createResource(localName, attrs);
68             return true;
69         }
70         else if (localName == "implementation") {
71             m_state = eXBL_InImplementation;
72             createImplementation(attrs);
73             return true;
74         }
75         else if (m_state == eXBL_InImplementation) {
76             if (localName == "constructor") {
77                 m_secondaryState = eXBL_InConstructor;
78                 createConstructor();
79             }
80             else if (localName == "destructor") {
81                 m_secondaryState = eXBL_InDestructor;
82                 createDestructor();
83             }
84             else if (localName == "field") {
85                 m_secondaryState = eXBL_InField;
86                 createField(attrs);
87             }
88             else if (localName == "property") {
89                 m_secondaryState = eXBL_InProperty;
90                 createProperty(attrs);
91             }
92             else if (localName == "getter")
93                 m_secondaryState = eXBL_InGetter;
94             else if (localName == "setter")
95                 m_secondaryState = eXBL_InSetter;
96             else if (localName == "method") {
97                 m_secondaryState = eXBL_InMethod;
98                 createMethod(attrs);
99             }
100             else if (localName == "parameter")
101                 createParameter(attrs);
102             else if (localName == "body")
103                 m_secondaryState = eXBL_InBody;
104             
105             return true; // Ignore everything we encounter inside an <implementation> block.
106         }        
107     }
108     
109     if (!XMLHandler::startElement(namespaceURI, localName, qName, attrs))
110         return false;
111     
112     // Create our binding if it doesn't exist already.
113     if (m_state == eXBL_InBinding && !m_binding)
114         createBinding();
115     
116     return true;
117 }
118
119 bool XBLTokenHandler::endElement(const QString& namespaceURI, const QString& localName, const QString& qName)
120 {
121     if (m_state != eXBL_InDocument) {
122         if (namespaceURI == xblNS) {
123             if (m_state == eXBL_InContent && localName == "content")
124                 m_state = eXBL_InBinding;
125             else if (m_state == eXBL_InHandlers) {
126                 if (localName == "handlers") {
127                     m_state = eXBL_InBinding;
128                     m_handler = 0;
129                 }
130                 else if (localName == "handler")
131                     m_secondaryState = eXBL_None;
132                 return true;
133             }
134             else if (m_state == eXBL_InResources) {
135                 if (localName == "resources")
136                     m_state = eXBL_InBinding;
137                 return true;
138             }
139             else if (m_state == eXBL_InImplementation) {
140                 if (localName == "implementation")
141                     m_state = eXBL_InBinding;
142                 else if (localName == "property") {
143                     m_secondaryState = eXBL_None;
144                     m_property = 0;
145                 }
146                 else if (localName == "method") {
147                     m_secondaryState = eXBL_None;
148                     m_method = 0;
149                 }
150                 else if (localName == "field") {
151                     m_secondaryState = eXBL_None;
152                     m_field = 0;
153                 }
154                 else if (localName == "constructor" ||
155                          localName == "destructor")
156                     m_secondaryState = eXBL_None;
157                 else if (localName == "getter" ||
158                          localName == "setter")
159                     m_secondaryState = eXBL_InProperty;
160                 else if (localName == "parameter" ||
161                          localName == "body")
162                     m_secondaryState = eXBL_InMethod;
163                 return true;
164             }
165             
166             if (!XMLHandler::endElement(namespaceURI, localName, qName))
167                 return false;
168             
169             if (m_state == eXBL_InImplementation && localName == "implementation")
170                 m_state = eXBL_InBinding;
171             else if (m_state == eXBL_InBinding && localName == "binding") {
172                 m_state = eXBL_InDocument;
173                 m_binding->initialize();
174                 m_binding = 0;
175             }
176             return true;
177         }
178     }
179     
180     return XMLHandler::endElement(namespaceURI, localName, qName);
181 }
182
183 bool XBLTokenHandler::characters(const QString& text)
184 {
185     if (text.length() == 0)
186         return true;
187     
188     if (m_state == eXBL_InHandlers) {
189         // Get the text and add it to the event handler.
190         if (m_secondaryState == eXBL_InHandler)
191             m_handler->appendData(text);
192         return true;
193     }
194     else if (m_state == eXBL_InImplementation) {
195         if (m_secondaryState == eXBL_InConstructor || m_secondaryState == eXBL_InDestructor || m_secondaryState == eXBL_InBody) {
196             if (m_method)
197                 m_method->appendData(text);
198         }
199         else if (m_secondaryState == eXBL_InGetter)
200             m_property->appendGetterText(text);
201         else if (m_secondaryState == eXBL_InSetter)
202             m_property->appendSetterText(text);
203         else if (m_secondaryState == eXBL_InField)
204             m_field->appendData(text);
205         return true;
206     }
207
208     // XBL files munch all whitespace, except when inside an anonymous content template (<content>).
209     if (m_state != eXBL_InContent) {
210         uint l = text.length();
211         uint i;
212         for (i = 0; i < l; i++) {
213             if (!isspace(text[i].unicode()))
214                 break;
215         }
216         if (i == l)
217             return true;
218     }
219     
220     return XMLHandler::characters(text);
221 }
222
223 void XBLTokenHandler::createBinding()
224 {
225     if (!m_currentNode || m_currentNode->nodeType() != Node::ELEMENT_NODE)
226         return;
227     
228     ElementImpl* elt = static_cast<ElementImpl*>(m_currentNode);
229     DOMString id = elt->getAttribute(ATTR_ID);
230     if (!id.isEmpty()) {
231         m_binding = new XBLPrototypeBinding(id, elt);
232         int exCode;
233         elt->removeAttribute(ATTR_ID, exCode);
234     }
235 }
236
237 void XBLTokenHandler::createHandler(const QXmlAttributes& attrs)
238 {
239     DOMString event;
240     DOMString modifiers;
241     DOMString button;
242     DOMString clickcount;
243     DOMString keycode;
244     DOMString charcode;
245     DOMString phase;
246     DOMString action;
247     DOMString preventdefault;
248     
249     int i;
250     for (i = 0; i < attrs.length(); i++) {
251         if (attrs.uri(i).length() > 0)
252             continue; // Only care about attributes with no namespace.
253         
254         if (attrs.qName(i) == "event")
255             event = attrs.value(i);
256         else if (attrs.qName(i) == "modifiers")
257             modifiers = attrs.value(i);
258         else if (attrs.qName(i) == "button")
259             button = attrs.value(i);
260         else if (attrs.qName(i) == "clickcount")
261             clickcount = attrs.value(i);
262         else if (attrs.qName(i) == "keycode")
263             keycode = attrs.value(i);
264         else if (attrs.qName(i) == "key" || attrs.qName(i) == "charcode")
265             charcode = attrs.value(i);
266         else if (attrs.qName(i) == "phase")
267             phase = attrs.value(i);
268         else if (attrs.qName(i) == "action")
269             action = attrs.value(i);
270         else if (attrs.qName(i) == "preventdefault")
271             preventdefault = attrs.value(i);
272     }
273     
274     XBLPrototypeHandler* newHandler = new XBLPrototypeHandler(event, phase, action, keycode, 
275                                                               charcode, modifiers, button,
276                                                               clickcount, preventdefault, m_binding);
277     if (newHandler) {
278         // Add this handler to our chain of handlers.
279         if (m_handler)
280             m_handler->setNext(newHandler); // Already have a chain. Just append to the end.
281         else
282             m_binding->setHandler(newHandler); // We're the first handler in the chain.
283         m_handler = newHandler; // Adjust our m_handler pointer to point to the new last handler in the chain.
284     }
285 }
286
287 void XBLTokenHandler::createResource(const QString& localName, const QXmlAttributes& attrs)
288 {
289     if (!m_binding)
290         return;
291     
292     for (int i = 0; i < attrs.length(); i++) {
293         if (attrs.uri(i).length() > 0)
294             continue;
295         
296         if (attrs.qName(i) == "src") {
297             m_binding->addResource(localName, attrs.value(i));
298             break;
299         }
300     }
301 }
302
303 void XBLTokenHandler::createImplementation(const QXmlAttributes& attrs)
304 {
305     m_implementation = 0;
306     m_member = 0;
307     
308     if (!m_binding)
309         return;
310     
311     DOMString name;    
312     for (int i = 0; i < attrs.length(); i++) {
313         if (attrs.uri(i).length() > 0)
314             continue;
315         
316         if (attrs.qName(i) == "name")
317             name = attrs.value(i);
318         else if (attrs.qName(i) == "implements") {
319             // FIXME: If we implement any sort of interface language binding, then we can parse the list of
320             // implemented interfaces here.
321             // m_binding->constructInterfaceTable(attrs.value(i));
322         }
323     }
324     
325     m_implementation = new XBLPrototypeImplementation(name, m_binding);
326 }
327
328 void XBLTokenHandler::addMember(XBLPrototypeMember* member)
329 {
330     if (m_member)
331         m_member->setNext(member);
332     else
333         m_implementation->setMember(member);
334     m_member = member;
335 }
336
337 void XBLTokenHandler::createConstructor()
338 {
339     m_method = new XBLPrototypeConstructor();
340     addMember(m_method);
341 }
342
343 void XBLTokenHandler::createDestructor()
344 {
345     m_method = new XBLPrototypeDestructor();
346     addMember(m_method);
347 }
348
349 void XBLTokenHandler::createField(const QXmlAttributes& attrs)
350 {
351     DOMString name;
352     bool readonly = false;
353     for (int i = 0; i < attrs.length(); i++) {
354         if (attrs.uri(i).length() > 0)
355             continue;
356         if (attrs.qName(i) == "name")
357             name = attrs.value(i);
358         else if (attrs.qName(i) == "readonly")
359             readonly = !(strcasecmp(attrs.value(i), "true"));
360     }
361     
362     m_field = new XBLPrototypeField(name, readonly);
363     addMember(m_field);
364 }
365
366 void XBLTokenHandler::createProperty(const QXmlAttributes& attrs)
367 {
368     DOMString name, onget, onset;
369     bool readonly = false;
370     for (int i = 0; i < attrs.length(); i++) {
371         if (attrs.uri(i).length() > 0)
372             continue;
373         if (attrs.qName(i) == "name")
374             name = attrs.value(i);
375         else if (attrs.qName(i) == "readonly")
376             readonly = !(strcasecmp(attrs.value(i), "true"));
377         else if (attrs.qName(i) == "onget")
378             onget = attrs.value(i);
379         else if (attrs.qName(i) == "onset")
380             onset = attrs.value(i);
381     }
382     
383     m_property = new XBLPrototypeProperty(name, readonly, onget, onset);
384     addMember(m_property);
385 }
386
387 void XBLTokenHandler::createMethod(const QXmlAttributes& attrs)
388 {
389     DOMString name;
390     for (int i = 0; i < attrs.length(); i++) {
391         if (attrs.uri(i).length() > 0)
392             continue;
393         if (attrs.qName(i) == "name")
394             name = attrs.value(i);
395     }
396     
397     m_method = new XBLPrototypeMethod(name);
398     addMember(m_method);
399 }
400
401 void XBLTokenHandler::createParameter(const QXmlAttributes& attrs)
402 {
403     if (!m_method) return;
404
405     for (int i = 0; i < attrs.length(); i++) {
406         if (attrs.uri(i).length() > 0)
407             continue;
408         
409         if (attrs.qName(i) == "name") {
410             m_method->addParameter(attrs.value(i));
411             break;
412         }
413     }
414 }
415
416 }
417
418 #endif