mutation.c 23.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Copyright 2008 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"

#include <stdarg.h>
22
#include <assert.h>
23 24 25 26 27 28 29 30

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
#include "ole2.h"
31
#include "shlguid.h"
32 33

#include "mshtml_private.h"
34
#include "htmlscript.h"
35
#include "htmlevent.h"
36
#include "binding.h"
37 38 39 40 41

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(mshtml);

42 43 44
#define IE_MAJOR_VERSION 7
#define IE_MINOR_VERSION 0

45 46 47 48 49
static const IID NS_ICONTENTUTILS_CID =
    {0x762C4AE7,0xB923,0x422F,{0xB9,0x7E,0xB9,0xBF,0xC1,0xEF,0x7B,0xF0}};

static nsIContentUtils *content_utils;

50
static PRUnichar *handle_insert_comment(HTMLDocumentNode *doc, const PRUnichar *comment)
51 52 53 54
{
    int majorv = 0, minorv = 0;
    const PRUnichar *ptr, *end;
    PRUnichar *buf;
55
    DWORD len;
56 57 58 59 60 61 62 63 64 65 66 67

    enum {
        CMP_EQ,
        CMP_LT,
        CMP_LTE,
        CMP_GT,
        CMP_GTE
    } cmpt = CMP_EQ;

    static const PRUnichar endifW[] = {'<','!','[','e','n','d','i','f',']'};

    if(comment[0] != '[' || comment[1] != 'i' || comment[2] != 'f')
68
        return NULL;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92

    ptr = comment+3;
    while(isspaceW(*ptr))
        ptr++;

    if(ptr[0] == 'l' && ptr[1] == 't') {
        ptr += 2;
        if(*ptr == 'e') {
            cmpt = CMP_LTE;
            ptr++;
        }else {
            cmpt = CMP_LT;
        }
    }else if(ptr[0] == 'g' && ptr[1] == 't') {
        ptr += 2;
        if(*ptr == 'e') {
            cmpt = CMP_GTE;
            ptr++;
        }else {
            cmpt = CMP_GT;
        }
    }

    if(!isspaceW(*ptr++))
93
        return NULL;
94 95 96 97
    while(isspaceW(*ptr))
        ptr++;

    if(ptr[0] != 'I' || ptr[1] != 'E')
98
        return NULL;
99 100 101

    ptr +=2;
    if(!isspaceW(*ptr++))
102
        return NULL;
103 104 105 106
    while(isspaceW(*ptr))
        ptr++;

    if(!isdigitW(*ptr))
107
        return NULL;
108 109 110 111
    while(isdigitW(*ptr))
        majorv = majorv*10 + (*ptr++ - '0');

    if(*ptr == '.') {
112
        ptr++;
113
        if(!isdigitW(*ptr))
114
            return NULL;
115 116 117 118 119 120 121
        while(isdigitW(*ptr))
            minorv = minorv*10 + (*ptr++ - '0');
    }

    while(isspaceW(*ptr))
        ptr++;
    if(ptr[0] != ']' || ptr[1] != '>')
122
        return NULL;
123 124 125 126
    ptr += 2;

    len = strlenW(ptr);
    if(len < sizeof(endifW)/sizeof(WCHAR))
127
        return NULL;
128 129 130

    end = ptr + len-sizeof(endifW)/sizeof(WCHAR);
    if(memcmp(end, endifW, sizeof(endifW)))
131
        return NULL;
132 133 134 135 136

    switch(cmpt) {
    case CMP_EQ:
        if(majorv == IE_MAJOR_VERSION && minorv == IE_MINOR_VERSION)
            break;
137
        return NULL;
138 139 140 141 142
    case CMP_LT:
        if(majorv > IE_MAJOR_VERSION)
            break;
        if(majorv == IE_MAJOR_VERSION && minorv > IE_MINOR_VERSION)
            break;
143
        return NULL;
144 145 146 147 148
    case CMP_LTE:
        if(majorv > IE_MAJOR_VERSION)
            break;
        if(majorv == IE_MAJOR_VERSION && minorv >= IE_MINOR_VERSION)
            break;
149
        return NULL;
150 151 152 153 154
    case CMP_GT:
        if(majorv < IE_MAJOR_VERSION)
            break;
        if(majorv == IE_MAJOR_VERSION && minorv < IE_MINOR_VERSION)
            break;
155
        return NULL;
156 157 158 159 160
    case CMP_GTE:
        if(majorv < IE_MAJOR_VERSION)
            break;
        if(majorv == IE_MAJOR_VERSION && minorv <= IE_MINOR_VERSION)
            break;
161
        return NULL;
162 163 164 165
    }

    buf = heap_alloc((end-ptr+1)*sizeof(WCHAR));
    if(!buf)
166
        return NULL;
167 168 169 170

    memcpy(buf, ptr, (end-ptr)*sizeof(WCHAR));
    buf[end-ptr] = 0;

171
    return buf;
172 173
}

174
static nsresult run_insert_comment(HTMLDocumentNode *doc, nsISupports *comment_iface, nsISupports *arg2)
175
{
176 177
    const PRUnichar *comment;
    nsIDOMComment *nscomment;
178
    PRUnichar *replace_html;
179
    nsAString comment_str;
180 181
    nsresult nsres;

182
    nsres = nsISupports_QueryInterface(comment_iface, &IID_nsIDOMComment, (void**)&nscomment);
183
    if(NS_FAILED(nsres)) {
184 185
        ERR("Could not get nsIDOMComment iface:%08x\n", nsres);
        return nsres;
186 187
    }

188 189 190 191 192 193
    nsAString_Init(&comment_str, NULL);
    nsres = nsIDOMComment_GetData(nscomment, &comment_str);
    if(NS_FAILED(nsres))
        return nsres;

    nsAString_GetData(&comment_str, &comment);
194
    replace_html = handle_insert_comment(doc, comment);
195 196
    nsAString_Finish(&comment_str);

197 198
    if(replace_html) {
        HRESULT hres;
199

200 201 202 203
        hres = replace_node_by_html(doc->nsdoc, (nsIDOMNode*)nscomment, replace_html);
        heap_free(replace_html);
        if(FAILED(hres))
            nsres = NS_ERROR_FAILURE;
204 205
    }

206

207
    nsIDOMComment_Release(nscomment);
208
    return nsres;
209 210
}

211
static nsresult run_bind_to_tree(HTMLDocumentNode *doc, nsISupports *nsiface, nsISupports *arg2)
212
{
213 214
    nsIDOMNode *nsnode;
    HTMLDOMNode *node;
215
    nsresult nsres;
216
    HRESULT hres;
217

218 219
    TRACE("(%p)->(%p)\n", doc, nsiface);

220 221
    nsres = nsISupports_QueryInterface(nsiface, &IID_nsIDOMNode, (void**)&nsnode);
    if(NS_FAILED(nsres))
222
        return nsres;
223

224
    hres = get_node(doc, nsnode, TRUE, &node);
225
    nsIDOMNode_Release(nsnode);
226
    if(FAILED(hres)) {
227
        ERR("Could not get node\n");
228
        return nsres;
229
    }
230

231 232
    if(node->vtbl->bind_to_tree)
        node->vtbl->bind_to_tree(node);
233

234
    node_release(node);
235
    return nsres;
236 237
}

238 239
/* Calls undocumented 69 cmd of CGID_Explorer */
static void call_explorer_69(HTMLDocumentObj *doc)
240
{
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    IOleCommandTarget *olecmd;
    VARIANT var;
    HRESULT hres;

    if(!doc->client)
        return;

    hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
    if(FAILED(hres))
        return;

    VariantInit(&var);
    hres = IOleCommandTarget_Exec(olecmd, &CGID_Explorer, 69, 0, NULL, &var);
    IOleCommandTarget_Release(olecmd);
    if(SUCCEEDED(hres) && V_VT(&var) != VT_NULL)
        FIXME("handle result\n");
}

259
static void parse_complete(HTMLDocumentObj *doc)
260 261 262 263 264 265 266
{
    TRACE("(%p)\n", doc);

    if(doc->usermode == EDITMODE)
        init_editor(&doc->basedoc);

    call_explorer_69(doc);
267 268
    if(doc->view_sink)
        IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
269
    call_property_onchanged(&doc->basedoc.cp_container, 1005);
270 271
    call_explorer_69(doc);

272
    if(doc->webbrowser && doc->usermode != EDITMODE && !(doc->basedoc.window->load_flags & BINDING_REFRESH))
273
        IDocObjectService_FireNavigateComplete2(doc->doc_object_service, &doc->basedoc.window->base.IHTMLWindow2_iface, 0);
274

275
    /* FIXME: IE7 calls EnableModelless(TRUE), EnableModelless(FALSE) and sets interactive state here */
276 277
}

278
static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISupports *arg2)
279
{
280
    TRACE("(%p)\n", This);
281

282
    if(!This->basedoc.doc_obj)
283
        return NS_OK;
284

285 286 287 288 289 290
    if(This == This->basedoc.doc_obj->basedoc.doc_node) {
        /*
         * This should be done in the worker thread that parses HTML,
         * but we don't have such thread (Gecko parses HTML for us).
         */
        parse_complete(This->basedoc.doc_obj);
291
    }
292

293
    bind_event_scripts(This);
294
    set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE);
295
    return NS_OK;
296 297
}

298
static nsresult run_insert_script(HTMLDocumentNode *doc, nsISupports *script_iface, nsISupports *parser_iface)
299
{
300
    nsIDOMHTMLScriptElement *nsscript;
301
    HTMLScriptElement *script_elem;
302
    nsIParser *nsparser = NULL;
303
    script_queue_entry_t *iter;
304
    HTMLInnerWindow *window;
305
    nsresult nsres;
306
    HRESULT hres;
307

308
    TRACE("(%p)->(%p)\n", doc, script_iface);
309

310 311 312 313
    window = doc->window;
    if(!window)
        return NS_OK;

314 315 316 317 318
    nsres = nsISupports_QueryInterface(script_iface, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
    if(NS_FAILED(nsres)) {
        ERR("Could not get nsIDOMHTMLScriptElement: %08x\n", nsres);
        return nsres;
    }
319

320 321 322 323 324 325 326 327
    if(parser_iface) {
        nsres = nsISupports_QueryInterface(parser_iface, &IID_nsIParser, (void**)&nsparser);
        if(NS_FAILED(nsres)) {
            ERR("Could not get nsIParser iface: %08x\n", nsres);
            nsparser = NULL;
        }
    }

328 329 330 331 332
    hres = script_elem_from_nsscript(doc, nsscript, &script_elem);
    nsIDOMHTMLScriptElement_Release(nsscript);
    if(FAILED(hres))
        return NS_ERROR_FAILURE;

333
    if(nsparser) {
334
        nsIParser_BeginEvaluatingParserInsertedScript(nsparser);
335 336
        window->parser_callback_cnt++;
    }
337

338 339
    IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface);

340
    doc_insert_script(window, script_elem);
341

342 343 344
    while(!list_empty(&window->script_queue)) {
        iter = LIST_ENTRY(list_head(&window->script_queue), script_queue_entry_t, entry);
        list_remove(&iter->entry);
345 346
        if(!iter->script->parsed)
            doc_insert_script(window, iter->script);
347 348 349 350 351 352
        IHTMLScriptElement_Release(&iter->script->IHTMLScriptElement_iface);
        heap_free(iter);
    }

    IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface);

353
    if(nsparser) {
354
        window->parser_callback_cnt--;
355 356 357 358
        nsIParser_EndEvaluatingParserInsertedScript(nsparser);
        nsIParser_Release(nsparser);
    }

359
    IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
360

361 362
    return NS_OK;
}
363

364
typedef struct nsRunnable nsRunnable;
365

366
typedef nsresult (*runnable_proc_t)(HTMLDocumentNode*,nsISupports*,nsISupports*);
367

368 369
struct nsRunnable {
    nsIRunnable  nsIRunnable_iface;
370

371
    LONG ref;
372

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
    runnable_proc_t proc;

    HTMLDocumentNode *doc;
    nsISupports *arg1;
    nsISupports *arg2;
};

static inline nsRunnable *impl_from_nsIRunnable(nsIRunnable *iface)
{
    return CONTAINING_RECORD(iface, nsRunnable, nsIRunnable_iface);
}

static nsresult NSAPI nsRunnable_QueryInterface(nsIRunnable *iface,
        nsIIDRef riid, void **result)
{
    nsRunnable *This = impl_from_nsIRunnable(iface);

    if(IsEqualGUID(riid, &IID_nsISupports)) {
        TRACE("(%p)->(IID_nsISupports %p)\n", This, result);
        *result = &This->nsIRunnable_iface;
    }else if(IsEqualGUID(riid, &IID_nsIRunnable)) {
        TRACE("(%p)->(IID_nsIRunnable %p)\n", This, result);
        *result = &This->nsIRunnable_iface;
    }else {
        *result = NULL;
        WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
        return NS_NOINTERFACE;
    }

    nsISupports_AddRef((nsISupports*)*result);
    return NS_OK;
}
405

406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
static nsrefcnt NSAPI nsRunnable_AddRef(nsIRunnable *iface)
{
    nsRunnable *This = impl_from_nsIRunnable(iface);
    LONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    return ref;
}

static nsrefcnt NSAPI nsRunnable_Release(nsIRunnable *iface)
{
    nsRunnable *This = impl_from_nsIRunnable(iface);
    LONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) ref=%d\n", This, ref);

    if(!ref) {
        htmldoc_release(&This->doc->basedoc);
        if(This->arg1)
            nsISupports_Release(This->arg1);
        if(This->arg2)
            nsISupports_Release(This->arg2);
        heap_free(This);
430 431
    }

432 433 434 435 436 437 438 439
    return ref;
}

static nsresult NSAPI nsRunnable_Run(nsIRunnable *iface)
{
    nsRunnable *This = impl_from_nsIRunnable(iface);

    return This->proc(This->doc, This->arg1, This->arg2);
440 441 442 443 444 445 446 447 448
}

static const nsIRunnableVtbl nsRunnableVtbl = {
    nsRunnable_QueryInterface,
    nsRunnable_AddRef,
    nsRunnable_Release,
    nsRunnable_Run
};

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
static void add_script_runner(HTMLDocumentNode *This, runnable_proc_t proc, nsISupports *arg1, nsISupports *arg2)
{
    nsRunnable *runnable;

    runnable = heap_alloc_zero(sizeof(*runnable));
    if(!runnable)
        return;

    runnable->nsIRunnable_iface.lpVtbl = &nsRunnableVtbl;
    runnable->ref = 1;

    htmldoc_addref(&This->basedoc);
    runnable->doc = This;
    runnable->proc = proc;

    if(arg1)
        nsISupports_AddRef(arg1);
    runnable->arg1 = arg1;

    if(arg2)
        nsISupports_AddRef(arg2);
    runnable->arg2 = arg2;

472
    nsIContentUtils_AddScriptRunner(content_utils, &runnable->nsIRunnable_iface);
473 474 475 476

    nsIRunnable_Release(&runnable->nsIRunnable_iface);
}

477 478 479 480
static inline HTMLDocumentNode *impl_from_nsIDocumentObserver(nsIDocumentObserver *iface)
{
    return CONTAINING_RECORD(iface, HTMLDocumentNode, nsIDocumentObserver_iface);
}
481 482

static nsresult NSAPI nsDocumentObserver_QueryInterface(nsIDocumentObserver *iface,
483
        nsIIDRef riid, void **result)
484
{
485
    HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
486 487 488

    if(IsEqualGUID(&IID_nsISupports, riid)) {
        TRACE("(%p)->(IID_nsISupports, %p)\n", This, result);
489
        *result = &This->nsIDocumentObserver_iface;
490 491
    }else if(IsEqualGUID(&IID_nsIMutationObserver, riid)) {
        TRACE("(%p)->(IID_nsIMutationObserver %p)\n", This, result);
492
        *result = &This->nsIDocumentObserver_iface;
493 494
    }else if(IsEqualGUID(&IID_nsIDocumentObserver, riid)) {
        TRACE("(%p)->(IID_nsIDocumentObserver %p)\n", This, result);
495
        *result = &This->nsIDocumentObserver_iface;
496 497 498 499 500 501
    }else {
        *result = NULL;
        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), result);
        return NS_NOINTERFACE;
    }

502
    htmldoc_addref(&This->basedoc);
503 504 505 506 507
    return NS_OK;
}

static nsrefcnt NSAPI nsDocumentObserver_AddRef(nsIDocumentObserver *iface)
{
508
    HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
509
    return htmldoc_addref(&This->basedoc);
510 511 512 513
}

static nsrefcnt NSAPI nsDocumentObserver_Release(nsIDocumentObserver *iface)
{
514
    HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
515
    return htmldoc_release(&This->basedoc);
516 517 518 519 520 521 522 523 524 525 526 527
}

static void NSAPI nsDocumentObserver_CharacterDataWillChange(nsIDocumentObserver *iface,
        nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
{
}

static void NSAPI nsDocumentObserver_CharacterDataChanged(nsIDocumentObserver *iface,
        nsIDocument *aDocument, nsIContent *aContent, void /*CharacterDataChangeInfo*/ *aInfo)
{
}

528
static void NSAPI nsDocumentObserver_AttributeWillChange(nsIDocumentObserver *iface, nsIDocument *aDocument,
529
        nsIContent *aContent, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType)
530 531 532
{
}

533
static void NSAPI nsDocumentObserver_AttributeChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
534
        nsIContent *aContent, LONG aNameSpaceID, nsIAtom *aAttribute, LONG aModType)
535 536 537
{
}

538
static void NSAPI nsDocumentObserver_AttributeSetToCurrentValue(nsIDocumentObserver *iface, nsIDocument *aDocument,
539
        void *aElement, LONG aNameSpaceID, nsIAtom *aAttribute)
540 541 542
{
}

543
static void NSAPI nsDocumentObserver_ContentAppended(nsIDocumentObserver *iface, nsIDocument *aDocument,
544
        nsIContent *aContainer, nsIContent *aFirstNewContent, LONG aNewIndexInContainer)
545 546 547 548
{
}

static void NSAPI nsDocumentObserver_ContentInserted(nsIDocumentObserver *iface, nsIDocument *aDocument,
549
        nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer)
550 551 552 553
{
}

static void NSAPI nsDocumentObserver_ContentRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
554
        nsIContent *aContainer, nsIContent *aChild, LONG aIndexInContainer,
555
        nsIContent *aProviousSibling)
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
{
}

static void NSAPI nsDocumentObserver_NodeWillBeDestroyed(nsIDocumentObserver *iface, const nsINode *aNode)
{
}

static void NSAPI nsDocumentObserver_ParentChainChanged(nsIDocumentObserver *iface, nsIContent *aContent)
{
}

static void NSAPI nsDocumentObserver_BeginUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
        nsUpdateType aUpdateType)
{
}

static void NSAPI nsDocumentObserver_EndUpdate(nsIDocumentObserver *iface, nsIDocument *aDocument,
        nsUpdateType aUpdateType)
{
}

static void NSAPI nsDocumentObserver_BeginLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
{
}

static void NSAPI nsDocumentObserver_EndLoad(nsIDocumentObserver *iface, nsIDocument *aDocument)
{
583
    HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
584

585
    TRACE("(%p)\n", This);
586

587 588 589
    if(This->skip_mutation_notif)
        return;

590
    This->content_ready = TRUE;
591
    add_script_runner(This, run_end_load, NULL, NULL);
592 593 594
}

static void NSAPI nsDocumentObserver_ContentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
595
        nsIContent *aContent, EventStates aStateMask)
596 597 598
{
}

599
static void NSAPI nsDocumentObserver_DocumentStatesChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
600
        EventStates aStateMask)
601 602 603
{
}

604
static void NSAPI nsDocumentObserver_StyleSheetAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
605
        nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
606 607 608 609
{
}

static void NSAPI nsDocumentObserver_StyleSheetRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
610
        nsIStyleSheet *aStyleSheet, cpp_bool aDocumentSheet)
611 612 613 614
{
}

static void NSAPI nsDocumentObserver_StyleSheetApplicableStateChanged(nsIDocumentObserver *iface,
615
        nsIDocument *aDocument, nsIStyleSheet *aStyleSheet, cpp_bool aApplicable)
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
{
}

static void NSAPI nsDocumentObserver_StyleRuleChanged(nsIDocumentObserver *iface, nsIDocument *aDocument,
        nsIStyleSheet *aStyleSheet, nsIStyleRule *aOldStyleRule, nsIStyleSheet *aNewStyleRule)
{
}

static void NSAPI nsDocumentObserver_StyleRuleAdded(nsIDocumentObserver *iface, nsIDocument *aDocument,
        nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
{
}

static void NSAPI nsDocumentObserver_StyleRuleRemoved(nsIDocumentObserver *iface, nsIDocument *aDocument,
        nsIStyleSheet *aStyleSheet, nsIStyleRule *aStyleRule)
{
}

static void NSAPI nsDocumentObserver_BindToDocument(nsIDocumentObserver *iface, nsIDocument *aDocument,
        nsIContent *aContent)
{
637
    HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
638
    nsIDOMHTMLIFrameElement *nsiframe;
639
    nsIDOMHTMLFrameElement *nsframe;
640
    nsIDOMHTMLScriptElement *nsscript;
641
    nsIDOMHTMLElement *nselem;
642 643 644
    nsIDOMComment *nscomment;
    nsresult nsres;

645
    TRACE("(%p)->(%p %p)\n", This, aDocument, aContent);
646

647
    nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLElement, (void**)&nselem);
648
    if(NS_SUCCEEDED(nsres)) {
649
        check_event_attr(This, nselem);
650
        nsIDOMHTMLElement_Release(nselem);
651 652
    }

653
    nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMComment, (void**)&nscomment);
654 655 656
    if(NS_SUCCEEDED(nsres)) {
        TRACE("comment node\n");

657
        add_script_runner(This, run_insert_comment, (nsISupports*)nscomment, NULL);
658
        nsIDOMComment_Release(nscomment);
659
        return;
660
    }
661

662
    nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLIFrameElement, (void**)&nsiframe);
663
    if(NS_SUCCEEDED(nsres)) {
664 665
        TRACE("iframe node\n");

666
        add_script_runner(This, run_bind_to_tree, (nsISupports*)nsiframe, NULL);
667
        nsIDOMHTMLIFrameElement_Release(nsiframe);
668
        return;
669
    }
670

671
    nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLFrameElement, (void**)&nsframe);
672 673 674
    if(NS_SUCCEEDED(nsres)) {
        TRACE("frame node\n");

675
        add_script_runner(This, run_bind_to_tree, (nsISupports*)nsframe, NULL);
676
        nsIDOMHTMLFrameElement_Release(nsframe);
677
        return;
678
    }
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

    nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
    if(NS_SUCCEEDED(nsres)) {
        HTMLScriptElement *script_elem;
        HRESULT hres;

        TRACE("script element\n");

        hres = script_elem_from_nsscript(This, nsscript, &script_elem);
        nsIDOMHTMLScriptElement_Release(nsscript);
        if(FAILED(hres))
            return;

        if(script_elem->parse_on_bind)
            add_script_runner(This, run_insert_script, (nsISupports*)nsscript, NULL);

        IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface);
    }
697 698
}

699
static void NSAPI nsDocumentObserver_AttemptToExecuteScript(nsIDocumentObserver *iface, nsIContent *aContent,
700
        nsIParser *aParser, cpp_bool *aBlock)
701
{
702
    HTMLDocumentNode *This = impl_from_nsIDocumentObserver(iface);
703 704 705
    nsIDOMHTMLScriptElement *nsscript;
    nsresult nsres;

706
    TRACE("(%p)->(%p %p %p)\n", This, aContent, aParser, aBlock);
707

708
    nsres = nsIContent_QueryInterface(aContent, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript);
709
    if(NS_SUCCEEDED(nsres)) {
710 711
        TRACE("script node\n");

712
        add_script_runner(This, run_insert_script, (nsISupports*)nsscript, (nsISupports*)aParser);
713 714 715 716 717 718 719 720 721 722
        nsIDOMHTMLScriptElement_Release(nsscript);
    }
}

static const nsIDocumentObserverVtbl nsDocumentObserverVtbl = {
    nsDocumentObserver_QueryInterface,
    nsDocumentObserver_AddRef,
    nsDocumentObserver_Release,
    nsDocumentObserver_CharacterDataWillChange,
    nsDocumentObserver_CharacterDataChanged,
723
    nsDocumentObserver_AttributeWillChange,
724
    nsDocumentObserver_AttributeChanged,
725
    nsDocumentObserver_AttributeSetToCurrentValue,
726 727 728 729 730 731 732 733 734 735
    nsDocumentObserver_ContentAppended,
    nsDocumentObserver_ContentInserted,
    nsDocumentObserver_ContentRemoved,
    nsDocumentObserver_NodeWillBeDestroyed,
    nsDocumentObserver_ParentChainChanged,
    nsDocumentObserver_BeginUpdate,
    nsDocumentObserver_EndUpdate,
    nsDocumentObserver_BeginLoad,
    nsDocumentObserver_EndLoad,
    nsDocumentObserver_ContentStatesChanged,
736
    nsDocumentObserver_DocumentStatesChanged,
737 738 739 740 741 742 743
    nsDocumentObserver_StyleSheetAdded,
    nsDocumentObserver_StyleSheetRemoved,
    nsDocumentObserver_StyleSheetApplicableStateChanged,
    nsDocumentObserver_StyleRuleChanged,
    nsDocumentObserver_StyleRuleAdded,
    nsDocumentObserver_StyleRuleRemoved,
    nsDocumentObserver_BindToDocument,
744
    nsDocumentObserver_AttemptToExecuteScript
745 746
};

747
void init_document_mutation(HTMLDocumentNode *doc)
748
{
749
    nsIDocument *nsdoc;
750 751
    nsresult nsres;

752
    doc->nsIDocumentObserver_iface.lpVtbl = &nsDocumentObserverVtbl;
753

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
    nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
    if(NS_FAILED(nsres)) {
        ERR("Could not get nsIDocument: %08x\n", nsres);
        return;
    }

    nsIContentUtils_AddDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
    nsIDocument_Release(nsdoc);
}

void release_document_mutation(HTMLDocumentNode *doc)
{
    nsIDocument *nsdoc;
    nsresult nsres;

    nsres = nsIDOMHTMLDocument_QueryInterface(doc->nsdoc, &IID_nsIDocument, (void**)&nsdoc);
770
    if(NS_FAILED(nsres)) {
771
        ERR("Could not get nsIDocument: %08x\n", nsres);
772 773 774
        return;
    }

775 776
    nsIContentUtils_RemoveDocumentObserver(content_utils, nsdoc, &doc->nsIDocumentObserver_iface);
    nsIDocument_Release(nsdoc);
777 778
}

779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
JSContext *get_context_from_document(nsIDOMHTMLDocument *nsdoc)
{
    nsIDocument *doc;
    JSContext *ctx;
    nsresult nsres;

    nsres = nsIDOMHTMLDocument_QueryInterface(nsdoc, &IID_nsIDocument, (void**)&doc);
    assert(nsres == NS_OK);

    ctx = nsIContentUtils_GetContextFromDocument(content_utils, doc);
    nsIDocument_Release(doc);

    TRACE("ret %p\n", ctx);
    return ctx;
}

795
void init_mutation(nsIComponentManager *component_manager)
796
{
797
    nsIFactory *factory;
798 799
    nsresult nsres;

800 801 802 803 804 805 806 807 808 809
    if(!component_manager) {
        if(content_utils) {
            nsIContentUtils_Release(content_utils);
            content_utils = NULL;
        }
        return;
    }

    nsres = nsIComponentManager_GetClassObject(component_manager, &NS_ICONTENTUTILS_CID,
            &IID_nsIFactory, (void**)&factory);
810
    if(NS_FAILED(nsres)) {
811
        ERR("Could not create nsIContentUtils service: %08x\n", nsres);
812 813 814
        return;
    }

815 816 817 818
    nsres = nsIFactory_CreateInstance(factory, NULL, &IID_nsIContentUtils, (void**)&content_utils);
    nsIFactory_Release(factory);
    if(NS_FAILED(nsres))
        ERR("Could not create nsIContentUtils instance: %08x\n", nsres);
819
}