Module: wine Branch: master Commit: 6bd162d9d2d18d328463962293560a00261b60c6 URL: https://gitlab.winehq.org/wine/wine/-/commit/6bd162d9d2d18d328463962293560a0...
Author: Gabriel Ivăncescu gabrielopcode@gmail.com Date: Wed Mar 8 19:36:07 2023 +0200
mshtml: Grab refs to windows upfront before sending pagehide events.
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com
---
dlls/mshtml/view.c | 74 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 23 deletions(-)
diff --git a/dlls/mshtml/view.c b/dlls/mshtml/view.c index 346fccf4955..3f31e609e39 100644 --- a/dlls/mshtml/view.c +++ b/dlls/mshtml/view.c @@ -414,45 +414,73 @@ HRESULT call_set_active_object(IOleInPlaceUIWindow *window, IOleInPlaceActiveObj return IOleInPlaceUIWindow_SetActiveObject(window, act_obj, act_obj ? html_documentW : NULL); }
-static void send_unload_events_impl(HTMLInnerWindow *window) +static unsigned get_window_list_num(HTMLInnerWindow *window) { HTMLOuterWindow *child; + unsigned ret = 1; + + LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) + ret += get_window_list_num(child->base.inner_window); + return ret; +} + +static HTMLInnerWindow **get_window_list(HTMLInnerWindow *window, HTMLInnerWindow **output) +{ + HTMLOuterWindow *child; + + *output++ = window; + IHTMLWindow2_AddRef(&window->base.IHTMLWindow2_iface); + + LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) + output = get_window_list(child->base.inner_window, output); + return output; +} + +static void send_unload_events(HTMLDocumentObj *doc) +{ + HTMLInnerWindow **windows, *window; DOMEvent *event; + unsigned i, num; HRESULT hres;
- if(!window) + if(!doc->window || !doc->doc_node->content_ready) + return; + window = doc->window->base.inner_window; + + /* Grab list of all windows ahead, and keep refs, + since it can be detached from under our feet. */ + num = get_window_list_num(window); + if(!(windows = malloc(num * sizeof(*windows)))) return; + get_window_list(window, windows); + + for(i = 0; i < num; i++) { + window = windows[i];
- if(window->doc && !window->doc->unload_sent) { - window->doc->unload_sent = TRUE; + if(window->doc && !window->doc->unload_sent) { + window->doc->unload_sent = TRUE; + + /* Native sends pagehide events prior to unload on the same window + before it moves on to the next window, so they're interleaved. */ + if(window->doc->document_mode >= COMPAT_MODE_IE11) { + hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + }
- /* Native sends pagehide events prior to unload on the same window - before it moves on to the next window, so they're interleaved. */ - if(window->doc->document_mode >= COMPAT_MODE_IE11) { - hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event); IDOMEvent_Release(&event->IDOMEvent_iface); } }
- hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); - if(SUCCEEDED(hres)) { - dispatch_event(&window->event_target, event); - IDOMEvent_Release(&event->IDOMEvent_iface); - } + IHTMLWindow2_Release(&window->base.IHTMLWindow2_iface); }
- LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) - send_unload_events_impl(child->base.inner_window); -} - -static void send_unload_events(HTMLDocumentObj *doc) -{ - if(!doc->window || !doc->doc_node->content_ready) - return; - - send_unload_events_impl(doc->window->base.inner_window); + free(windows); }
/**********************************************************