xref: /reactos/dll/win32/mshtml/mutation.c (revision c2c66aff)
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include "mshtml_private.h"
20 
21 #define IE_MAJOR_VERSION 7
22 #define IE_MINOR_VERSION 0
23 
24 static const IID NS_ICONTENTUTILS_CID =
25     {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};
26 
27 static nsIContentUtils *content_utils;
28 
handle_insert_comment(HTMLDocumentNode * doc,const PRUnichar * comment)29 static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
30 {
31     int majorv = 0, minorv = 0;
32     const PRUnichar *ptr, *end;
33     PRUnichar *buf;
34     DWORD len;
35 
36     enum {
37         CMP_EQ,
38         CMP_LT,
39         CMP_LTE,
40         CMP_GT,
41         CMP_GTE
42     } cmpt = CMP_EQ;
43 
44     static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};
45 
46     if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
47         return NULL;
48 
49     ptr = comment+3;
50     while(isspaceW(*ptr))
51         ptr++;
52 
53     if(ptr[0] == 'l' && ptr[1] == 't') {
54         ptr += 2;
55         if(*ptr == 'e') {
56             cmpt = CMP_LTE;
57             ptr++;
58         }else {
59             cmpt = CMP_LT;
60         }
61     }else if(ptr[0] == 'g' && ptr[1] == 't') {
62         ptr += 2;
63         if(*ptr == 'e') {
64             cmpt = CMP_GTE;
65             ptr++;
66         }else {
67             cmpt = CMP_GT;
68         }
69     }
70 
71     if(!isspaceW(*ptr++))
72         return NULL;
73     while(isspaceW(*ptr))
74         ptr++;
75 
76     if(ptr[0] != 'I' || ptr[1] != 'E')
77         return NULL;
78 
79     ptr +=2;
80     if(!isspaceW(*ptr++))
81         return NULL;
82     while(isspaceW(*ptr))
83         ptr++;
84 
85     if(!isdigitW(*ptr))
86         return NULL;
87     while(isdigitW(*ptr))
88         majorv = majorv*10 + (*ptr++ - '0');
89 
90     if(*ptr == '.') {
91         ptr++;
92         if(!isdigitW(*ptr))
93             return NULL;
94         while(isdigitW(*ptr))
95             minorv = minorv*10 + (*ptr++ - '0');
96     }
97 
98     while(isspaceW(*ptr))
99         ptr++;
100     if(ptr[0] != ']' || ptr[1] != '>')
101         return NULL;
102     ptr += 2;
103 
104     len = strlenW(ptr);
105     if(len < sizeof(endifW)/sizeof(WCHAR))
106         return NULL;
107 
108     end = ptr + len-sizeof(endifW)/sizeof(WCHAR);
109     if(memcmp(end, endifW, sizeof(endifW)))
110         return NULL;
111 
112     switch(cmpt) {
113     case CMP_EQ:
114         if(majorv == IE_MAJOR_VERSION && minorv == IE_MINOR_VERSION)
115             break;
116         return NULL;
117     case CMP_LT:
118         if(majorv > IE_MAJOR_VERSION)
119             break;
120         if(majorv == IE_MAJOR_VERSION && minorv > IE_MINOR_VERSION)
121             break;
122         return NULL;
123     case CMP_LTE:
124         if(majorv > IE_MAJOR_VERSION)
125             break;
126         if(majorv == IE_MAJOR_VERSION && minorv >= IE_MINOR_VERSION)
127             break;
128         return NULL;
129     case CMP_GT:
130         if(majorv < IE_MAJOR_VERSION)
131             break;
132         if(majorv == IE_MAJOR_VERSION && minorv < IE_MINOR_VERSION)
133             break;
134         return NULL;
135     case CMP_GTE:
136         if(majorv < IE_MAJOR_VERSION)
137             break;
138         if(majorv == IE_MAJOR_VERSION && minorv <= IE_MINOR_VERSION)
139             break;
140         return NULL;
141     }
142 
143     buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
144     if(!buf)
145         return NULL;
146 
147     memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
148     buf[end-ptr] = 0;
149 
150     return buf;
151 }
152 
run_insert_comment(HTMLDocumentNode * doc,nsISupports * comment_iface,nsISupports * arg2)153 static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
154 {
155     const PRUnichar *comment;
156     nsIDOMComment *nscomment;
157     PRUnichar *replace_html;
158     nsAString comment_str;
159     nsresult nsres;
160 
161     nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
162     if(NS_FAILED(nsres)) {
163         ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
164         return nsres;
165     }
166 
167     nsAString_Init(&comment_str, NULL);
168     nsres = nsIDOMComment_GetData(nscomment, &comment_str);
169     if(NS_FAILED(nsres))
170         return nsres;
171 
172     nsAString_GetData(&comment_str, &comment);
173     replace_html = handle_insert_comment(doc, comment);
174     nsAString_Finish(&comment_str);
175 
176     if(replace_html) {
177         HRESULT hres;
178 
179         hres = replace_node_by_html(doc->nsdoc, (nsIDOMNode*)nscomment, replace_html);
180         heap_free(replace_html);
181         if(FAILED(hres))
182             nsres = NS_ERROR_FAILURE;
183     }
184 
185 
186     nsIDOMComment_Release(nscomment);
187     return nsres;
188 }
189 
run_bind_to_tree(HTMLDocumentNode * doc,nsISupports * nsiface,nsISupports * arg2)190 static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
191 {
192     nsIDOMNode *nsnode;
193     HTMLDOMNode *node;
194     nsresult nsres;
195     HRESULT hres;
196 
197     TRACE("(%p)->(%p)\n", doc, nsiface);
198 
199     nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
200     if(NS_FAILED(nsres))
201         return nsres;
202 
203     hres = get_node(doc, nsnode, TRUE, &node);
204     nsIDOMNode_Release(nsnode);
205     if(FAILED(hres)) {
206         ERR("Could not get node\n");
207         return nsres;
208     }
209 
210     if(node->vtbl->bind_to_tree)
211         node->vtbl->bind_to_tree(node);
212 
213     node_release(node);
214     return nsres;
215 }
216 
217 /* Calls undocumented 69 cmd of CGID_Explorer */
call_explorer_69(HTMLDocumentObj * doc)218 static void call_explorer_69(HTMLDocumentObj *doc)
219 {
220     IOleCommandTarget *olecmd;
221     VARIANT var;
222     HRESULT hres;
223 
224     if(!doc->client)
225         return;
226 
227     hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
228     if(FAILED(hres))
229         return;
230 
231     VariantInit(&var);
232     hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
233     IOleCommandTarget_Release(olecmd);
234     if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
235         FIXME("handle result\n");
236 }
237 
parse_complete(HTMLDocumentObj * doc)238 static void parse_complete(HTMLDocumentObj *doc)
239 {
240     TRACE("(%p)\n", doc);
241 
242     if(doc->usermode == EDITMODE)
243         init_editor(&doc->basedoc);
244 
245     call_explorer_69(doc);
246     if(doc->view_sink)
247         IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
248     call_property_onchanged(&doc->basedoc.cp_container, 1005);
249     call_explorer_69(doc);
250 
251     if(doc->webbrowser && doc->usermode != EDITMODE && !(doc->basedoc.window->load_flags & BINDING_REFRESH))
252         IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
253 
254     /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
255 }
256 
run_end_load(HTMLDocumentNode * This,nsISupports * arg1,nsISupports * arg2)257 static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
258 {
259     TRACE("(%p)\n", This);
260 
261     if(!This->basedoc.doc_obj)
262         return NS_OK;
263 
264     if(This == This->basedoc.doc_obj->basedoc.doc_node) {
265         /*
266          * This should be done in the worker thread that parses HTML,
267          * but we don't have such thread (Gecko parses HTML for us).
268          */
269         parse_complete(This->basedoc.doc_obj);
270     }
271 
272     bind_event_scripts(This);
273     set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
274     return NS_OK;
275 }
276 
run_insert_script(HTMLDocumentNode * doc,nsISupports * script_iface,nsISupports * parser_iface)277 static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
278 {
279     nsIDOMHTMLScriptElement *nsscript;
280     HTMLScriptElement *script_elem;
281     nsIParser *nsparser = NULL;
282     script_queue_entry_t *iter;
283     HTMLInnerWindow *window;
284     nsresult nsres;
285     HRESULT hres;
286 
287     TRACE("(%p)->(%p)\n", doc, script_iface);
288 
289     window = doc->window;
290     if(!window)
291         return NS_OK;
292 
293     nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
294     if(NS_FAILED(nsres)) {
295         ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
296         return nsres;
297     }
298 
299     if(parser_iface) {
300         nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
301         if(NS_FAILED(nsres)) {
302             ERR("Could not get nsIParser iface: %08x\n", nsres);
303             nsparser = NULL;
304         }
305     }
306 
307     hres = script_elem_from_nsscript(doc, nsscript, &script_elem);
308     nsIDOMHTMLScriptElement_Release(nsscript);
309     if(FAILED(hres))
310         return NS_ERROR_FAILURE;
311 
312     if(nsparser) {
313         nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
314         window->parser_callback_cnt++;
315     }
316 
317     IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);
318 
319     doc_insert_script(window, script_elem);
320 
321     while(!list_empty(&window->script_queue)) {
322         iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
323         list_remove(&iter->entry);
324         if(!iter->script->parsed)
325             doc_insert_script(window, iter->script);
326         IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
327         heap_free(iter);
328     }
329 
330     IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);
331 
332     if(nsparser) {
333         window->parser_callback_cnt--;
334         nsIParser_EndEvaluatingParserInsertedScript(nsparser);
335         nsIParser_Release(nsparser);
336     }
337 
338     IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
339 
340     return NS_OK;
341 }
342 
343 typedef struct nsRunnable nsRunnable;
344 
345 typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
346 
347 struct nsRunnable {
348     nsIRunnable  nsIRunnable_iface;
349 
350     LONG ref;
351 
352     runnable_proc_t proc;
353 
354     HTMLDocumentNode *doc;
355     nsISupports *arg1;
356     nsISupports *arg2;
357 };
358 
impl_from_nsIRunnable(nsIRunnable * iface)359 static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
360 {
361     return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
362 }
363 
nsRunnable_QueryInterface(nsIRunnable * iface,nsIIDRef riid,void ** result)364 static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
365         nsIIDRef riid, void **result)
366 {
367     nsRunnable *This = impl_from_nsIRunnable(iface);
368 
369     if(IsEqualGUID(riid, &IID_nsISupports)) {
370         TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
371         *result = &This->nsIRunnable_iface;
372     }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
373         TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
374         *result = &This->nsIRunnable_iface;
375     }else {
376         *result = NULL;
377         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
378         return NS_NOINTERFACE;
379     }
380 
381     nsISupports_AddRef((nsISupports*)*result);
382     return NS_OK;
383 }
384 
nsRunnable_AddRef(nsIRunnable * iface)385 static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
386 {
387     nsRunnable *This = impl_from_nsIRunnable(iface);
388     LONG ref = InterlockedIncrement(&This->ref);
389 
390     TRACE("(%p) ref=%d\n", This, ref);
391 
392     return ref;
393 }
394 
nsRunnable_Release(nsIRunnable * iface)395 static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
396 {
397     nsRunnable *This = impl_from_nsIRunnable(iface);
398     LONG ref = InterlockedDecrement(&This->ref);
399 
400     TRACE("(%p) ref=%d\n", This, ref);
401 
402     if(!ref) {
403         htmldoc_release(&This->doc->basedoc);
404         if(This->arg1)
405             nsISupports_Release(This->arg1);
406         if(This->arg2)
407             nsISupports_Release(This->arg2);
408         heap_free(This);
409     }
410 
411     return ref;
412 }
413 
nsRunnable_Run(nsIRunnable * iface)414 static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
415 {
416     nsRunnable *This = impl_from_nsIRunnable(iface);
417 
418     return This->proc(This->doc, This->arg1, This->arg2);
419 }
420 
421 static const nsIRunnableVtbl nsRunnableVtbl = {
422     nsRunnable_QueryInterface,
423     nsRunnable_AddRef,
424     nsRunnable_Release,
425     nsRunnable_Run
426 };
427 
add_script_runner(HTMLDocumentNode * This,runnable_proc_t proc,nsISupports * arg1,nsISupports * arg2)428 static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
429 {
430     nsRunnable *runnable;
431 
432     runnable = heap_alloc_zero(sizeof(*runnable));
433     if(!runnable)
434         return;
435 
436     runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
437     runnable->ref = 1;
438 
439     htmldoc_addref(&This->basedoc);
440     runnable->doc = This;
441     runnable->proc = proc;
442 
443     if(arg1)
444         nsISupports_AddRef(arg1);
445     runnable->arg1 = arg1;
446 
447     if(arg2)
448         nsISupports_AddRef(arg2);
449     runnable->arg2 = arg2;
450 
451     nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
452 
453     nsIRunnable_Release(&runnable->nsIRunnable_iface);
454 }
455 
impl_from_nsIDocumentObserver(nsIDocumentObserver * iface)456 static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
457 {
458     return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
459 }
460 
nsDocumentObserver_QueryInterface(nsIDocumentObserver * iface,nsIIDRef riid,void ** result)461 static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
462         nsIIDRef riid, void **result)
463 {
464     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
465 
466     if(IsEqualGUID(&IID_nsISupports, riid)) {
467         TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
468         *result = &This->nsIDocumentObserver_iface;
469     }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
470         TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
471         *result = &This->nsIDocumentObserver_iface;
472     }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
473         TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
474         *result = &This->nsIDocumentObserver_iface;
475     }else {
476         *result = NULL;
477         TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
478         return NS_NOINTERFACE;
479     }
480 
481     htmldoc_addref(&This->basedoc);
482     return NS_OK;
483 }
484 
nsDocumentObserver_AddRef(nsIDocumentObserver * iface)485 static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
486 {
487     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
488     return htmldoc_addref(&This->basedoc);
489 }
490 
nsDocumentObserver_Release(nsIDocumentObserver * iface)491 static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
492 {
493     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
494     return htmldoc_release(&This->basedoc);
495 }
496 
nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContent,void * aInfo)497 static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
498         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
499 {
500 }
501 
nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContent,void * aInfo)502 static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
503         nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
504 {
505 }
506 
nsDocumentObserver_AttributeWillChange(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContent,LONG aNameSpaceID,nsIAtom * aAttribute,LONG aModType)507 static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
508         nsIContent *aContent, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType)
509 {
510 }
511 
nsDocumentObserver_AttributeChanged(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContent,LONG aNameSpaceID,nsIAtom * aAttribute,LONG aModType)512 static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
513         nsIContent *aContent, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType)
514 {
515 }
516 
nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver * iface,nsIDocument * aDocument,void * aElement,LONG aNameSpaceID,nsIAtom * aAttribute)517 static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
518         void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
519 {
520 }
521 
nsDocumentObserver_ContentAppended(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContainer,nsIContent * aFirstNewContent,LONG aNewIndexInContainer)522 static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
523         nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
524 {
525 }
526 
nsDocumentObserver_ContentInserted(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContainer,nsIContent * aChild,LONG aIndexInContainer)527 static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
528         nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
529 {
530 }
531 
nsDocumentObserver_ContentRemoved(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContainer,nsIContent * aChild,LONG aIndexInContainer,nsIContent * aProviousSibling)532 static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
533         nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
534         nsIContent *aProviousSibling)
535 {
536 }
537 
nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver * iface,const nsINode * aNode)538 static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
539 {
540 }
541 
nsDocumentObserver_ParentChainChanged(nsIDocumentObserver * iface,nsIContent * aContent)542 static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
543 {
544 }
545 
nsDocumentObserver_BeginUpdate(nsIDocumentObserver * iface,nsIDocument * aDocument,nsUpdateType aUpdateType)546 static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
547         nsUpdateType aUpdateType)
548 {
549 }
550 
nsDocumentObserver_EndUpdate(nsIDocumentObserver * iface,nsIDocument * aDocument,nsUpdateType aUpdateType)551 static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
552         nsUpdateType aUpdateType)
553 {
554 }
555 
nsDocumentObserver_BeginLoad(nsIDocumentObserver * iface,nsIDocument * aDocument)556 static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
557 {
558 }
559 
nsDocumentObserver_EndLoad(nsIDocumentObserver * iface,nsIDocument * aDocument)560 static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
561 {
562     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
563 
564     TRACE("(%p)\n", This);
565 
566     if(This->skip_mutation_notif)
567         return;
568 
569     This->content_ready = TRUE;
570     add_script_runner(This, run_end_load, NULL, NULL);
571 }
572 
nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContent,EventStates aStateMask)573 static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
574         nsIContent *aContent, EventStates aStateMask)
575 {
576 }
577 
nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver * iface,nsIDocument * aDocument,EventStates aStateMask)578 static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
579         EventStates aStateMask)
580 {
581 }
582 
nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIStyleSheet * aStyleSheet,cpp_bool aDocumentSheet)583 static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
584         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
585 {
586 }
587 
nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIStyleSheet * aStyleSheet,cpp_bool aDocumentSheet)588 static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
589         nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
590 {
591 }
592 
nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIStyleSheet * aStyleSheet,cpp_bool aApplicable)593 static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
594         nsIDocument *aDocument, nsIStyleSheet *aStyleSheet, cpp_bool aApplicable)
595 {
596 }
597 
nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIStyleSheet * aStyleSheet,nsIStyleRule * aOldStyleRule,nsIStyleSheet * aNewStyleRule)598 static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
599         nsIStyleSheet *aStyleSheet, nsIStyleRule *aOldStyleRule, nsIStyleSheet *aNewStyleRule)
600 {
601 }
602 
nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIStyleSheet * aStyleSheet,nsIStyleRule * aStyleRule)603 static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
604         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
605 {
606 }
607 
nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIStyleSheet * aStyleSheet,nsIStyleRule * aStyleRule)608 static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
609         nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
610 {
611 }
612 
nsDocumentObserver_BindToDocument(nsIDocumentObserver * iface,nsIDocument * aDocument,nsIContent * aContent)613 static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
614         nsIContent *aContent)
615 {
616     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
617     nsIDOMHTMLIFrameElement *nsiframe;
618     nsIDOMHTMLFrameElement *nsframe;
619     nsIDOMHTMLScriptElement *nsscript;
620     nsIDOMHTMLElement *nselem;
621     nsIDOMComment *nscomment;
622     nsresult nsres;
623 
624     TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
625 
626     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLElement, (void**)&nselem);
627     if(NS_SUCCEEDED(nsres)) {
628         check_event_attr(This, nselem);
629         nsIDOMHTMLElement_Release(nselem);
630     }
631 
632     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
633     if(NS_SUCCEEDED(nsres)) {
634         TRACE("comment node\n");
635 
636         add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
637         nsIDOMComment_Release(nscomment);
638         return;
639     }
640 
641     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
642     if(NS_SUCCEEDED(nsres)) {
643         TRACE("iframe node\n");
644 
645         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
646         nsIDOMHTMLIFrameElement_Release(nsiframe);
647         return;
648     }
649 
650     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
651     if(NS_SUCCEEDED(nsres)) {
652         TRACE("frame node\n");
653 
654         add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
655         nsIDOMHTMLFrameElement_Release(nsframe);
656         return;
657     }
658 
659     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
660     if(NS_SUCCEEDED(nsres)) {
661         HTMLScriptElement *script_elem;
662         HRESULT hres;
663 
664         TRACE("script element\n");
665 
666         hres = script_elem_from_nsscript(This, nsscript, &script_elem);
667         nsIDOMHTMLScriptElement_Release(nsscript);
668         if(FAILED(hres))
669             return;
670 
671         if(script_elem->parse_on_bind)
672             add_script_runner(This, run_insert_script, (nsISupports*)nsscript, NULL);
673 
674         IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
675     }
676 }
677 
nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver * iface,nsIContent * aContent,nsIParser * aParser,cpp_bool * aBlock)678 static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
679         nsIParser *aParser, cpp_bool *aBlock)
680 {
681     HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
682     nsIDOMHTMLScriptElement *nsscript;
683     nsresult nsres;
684 
685     TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
686 
687     nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
688     if(NS_SUCCEEDED(nsres)) {
689         TRACE("script node\n");
690 
691         add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
692         nsIDOMHTMLScriptElement_Release(nsscript);
693     }
694 }
695 
696 static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
697     nsDocumentObserver_QueryInterface,
698     nsDocumentObserver_AddRef,
699     nsDocumentObserver_Release,
700     nsDocumentObserver_CharacterDataWillChange,
701     nsDocumentObserver_CharacterDataChanged,
702     nsDocumentObserver_AttributeWillChange,
703     nsDocumentObserver_AttributeChanged,
704     nsDocumentObserver_AttributeSetToCurrentValue,
705     nsDocumentObserver_ContentAppended,
706     nsDocumentObserver_ContentInserted,
707     nsDocumentObserver_ContentRemoved,
708     nsDocumentObserver_NodeWillBeDestroyed,
709     nsDocumentObserver_ParentChainChanged,
710     nsDocumentObserver_BeginUpdate,
711     nsDocumentObserver_EndUpdate,
712     nsDocumentObserver_BeginLoad,
713     nsDocumentObserver_EndLoad,
714     nsDocumentObserver_ContentStatesChanged,
715     nsDocumentObserver_DocumentStatesChanged,
716     nsDocumentObserver_StyleSheetAdded,
717     nsDocumentObserver_StyleSheetRemoved,
718     nsDocumentObserver_StyleSheetApplicableStateChanged,
719     nsDocumentObserver_StyleRuleChanged,
720     nsDocumentObserver_StyleRuleAdded,
721     nsDocumentObserver_StyleRuleRemoved,
722     nsDocumentObserver_BindToDocument,
723     nsDocumentObserver_AttemptToExecuteScript
724 };
725 
init_document_mutation(HTMLDocumentNode * doc)726 void init_document_mutation(HTMLDocumentNode *doc)
727 {
728     nsIDocument *nsdoc;
729     nsresult nsres;
730 
731     doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
732 
733     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
734     if(NS_FAILED(nsres)) {
735         ERR("Could not get nsIDocument: %08x\n", nsres);
736         return;
737     }
738 
739     nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
740     nsIDocument_Release(nsdoc);
741 }
742 
release_document_mutation(HTMLDocumentNode * doc)743 void release_document_mutation(HTMLDocumentNode *doc)
744 {
745     nsIDocument *nsdoc;
746     nsresult nsres;
747 
748     nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
749     if(NS_FAILED(nsres)) {
750         ERR("Could not get nsIDocument: %08x\n", nsres);
751         return;
752     }
753 
754     nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
755     nsIDocument_Release(nsdoc);
756 }
757 
get_context_from_document(nsIDOMHTMLDocument * nsdoc)758 JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
759 {
760     nsIDocument *doc;
761     JSContext *ctx;
762     nsresult nsres;
763 
764     nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
765     assert(nsres == NS_OK);
766 
767     ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
768     nsIDocument_Release(doc);
769 
770     TRACE("ret %p\n", ctx);
771     return ctx;
772 }
773 
init_mutation(nsIComponentManager * component_manager)774 void init_mutation(nsIComponentManager *component_manager)
775 {
776     nsIFactory *factory;
777     nsresult nsres;
778 
779     if(!component_manager) {
780         if(content_utils) {
781             nsIContentUtils_Release(content_utils);
782             content_utils = NULL;
783         }
784         return;
785     }
786 
787     nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
788             &IID_nsIFactory, (void**)&factory);
789     if(NS_FAILED(nsres)) {
790         ERR("Could not create nsIContentUtils service: %08x\n", nsres);
791         return;
792     }
793 
794     nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
795     nsIFactory_Release(factory);
796     if(NS_FAILED(nsres))
797         ERR("Could not create nsIContentUtils instance: %08x\n", nsres);
798 }
799