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