From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 24 ++-- dlls/mshtml/htmlevent.c | 217 ++++++++++++++++++++++++++++++++++- dlls/mshtml/htmlevent.h | 3 + dlls/mshtml/htmlstorage.c | 74 +++++++++++- dlls/mshtml/htmlwindow.c | 10 +- dlls/mshtml/mshtml_private.h | 3 + 6 files changed, 317 insertions(+), 14 deletions(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index fe743e666c1..413a3a4054e 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3423,30 +3423,38 @@ static HRESULT WINAPI HTMLDocument6_get_onstorage(IHTMLDocument6 *iface, VARIANT *p) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return get_doc_event(This, EVENTID_STORAGE, p); }
static HRESULT WINAPI HTMLDocument6_put_onstorage(IHTMLDocument6 *iface, VARIANT v) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_doc_event(This, EVENTID_STORAGE, &v); }
static HRESULT WINAPI HTMLDocument6_get_onstoragecommit(IHTMLDocument6 *iface, VARIANT *p) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%p)\n", This, p); - return E_NOTIMPL; + + TRACE("(%p)->(%p)\n", This, p); + + return get_doc_event(This, EVENTID_STORAGECOMMIT, p); }
static HRESULT WINAPI HTMLDocument6_put_onstoragecommit(IHTMLDocument6 *iface, VARIANT v) { HTMLDocument *This = impl_from_IHTMLDocument6(iface); - FIXME("(%p)->(%s)\n", This, debugstr_variant(&v)); - return E_NOTIMPL; + + TRACE("(%p)->(%s)\n", This, debugstr_variant(&v)); + + return set_doc_event(This, EVENTID_STORAGECOMMIT, &v); }
static HRESULT WINAPI HTMLDocument6_getElementById(IHTMLDocument6 *iface, diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index a0b024fd65f..7d13ac5b3fb 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -191,6 +191,10 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"selectstart", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSELECTSTART, EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE}, + {L"storage", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSTORAGE, + 0}, + {L"storagecommit", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSTORAGECOMMIT, + 0}, {L"submit", EVENT_TYPE_EVENT, DISPID_EVMETH_ONSUBMIT, EVENT_DEFAULTLISTENER | EVENT_HASDEFAULTHANDLERS | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"timeout", EVENT_TYPE_PROGRESS, DISPID_EVPROP_TIMEOUT, @@ -2606,6 +2610,164 @@ static void DOMProgressEvent_destroy(DOMEvent *event) nsIDOMProgressEvent_Release(This->nsevent); }
+typedef struct { + DOMEvent event; + IDOMStorageEvent IDOMStorageEvent_iface; + BSTR key; + BSTR old_value; + BSTR new_value; +} DOMStorageEvent; + +static inline DOMStorageEvent *impl_from_IDOMStorageEvent(IDOMStorageEvent *iface) +{ + return CONTAINING_RECORD(iface, DOMStorageEvent, IDOMStorageEvent_iface); +} + +static HRESULT WINAPI DOMStorageEvent_QueryInterface(IDOMStorageEvent *iface, REFIID riid, void **ppv) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDOMEvent_QueryInterface(&This->event.IDOMEvent_iface, riid, ppv); +} + +static ULONG WINAPI DOMStorageEvent_AddRef(IDOMStorageEvent *iface) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDOMEvent_AddRef(&This->event.IDOMEvent_iface); +} + +static ULONG WINAPI DOMStorageEvent_Release(IDOMStorageEvent *iface) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDOMEvent_Release(&This->event.IDOMEvent_iface); +} + +static HRESULT WINAPI DOMStorageEvent_GetTypeInfoCount(IDOMStorageEvent *iface, UINT *pctinfo) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_GetTypeInfoCount(&This->event.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI DOMStorageEvent_GetTypeInfo(IDOMStorageEvent *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_GetTypeInfo(&This->event.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI DOMStorageEvent_GetIDsOfNames(IDOMStorageEvent *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_GetIDsOfNames(&This->event.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI DOMStorageEvent_Invoke(IDOMStorageEvent *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + return IDispatchEx_Invoke(&This->event.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI DOMStorageEvent_get_key(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + + TRACE("(%p)->(%p)\n", This, p); + + if(This->key) + return (*p = SysAllocStringLen(This->key, SysStringLen(This->key))) ? S_OK : E_OUTOFMEMORY; + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI DOMStorageEvent_get_oldValue(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + + TRACE("(%p)->(%p)\n", This, p); + + if(This->old_value) + return (*p = SysAllocStringLen(This->old_value, SysStringLen(This->old_value))) ? S_OK : E_OUTOFMEMORY; + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI DOMStorageEvent_get_newValue(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + + TRACE("(%p)->(%p)\n", This, p); + + if(This->new_value) + return (*p = SysAllocStringLen(This->new_value, SysStringLen(This->new_value))) ? S_OK : E_OUTOFMEMORY; + *p = NULL; + return S_OK; +} + +static HRESULT WINAPI DOMStorageEvent_get_url(IDOMStorageEvent *iface, BSTR *p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMStorageEvent_get_storageArea(IDOMStorageEvent *iface, IHTMLStorage **p) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + FIXME("(%p)->(%p)\n", This, p); + return E_NOTIMPL; +} + +static HRESULT WINAPI DOMStorageEvent_initStorageEvent(IDOMStorageEvent *iface, BSTR type, VARIANT_BOOL can_bubble, + VARIANT_BOOL cancelable, BSTR keyArg, BSTR oldValueArg, + BSTR newValueArg, BSTR urlArg, IHTMLStorage *storageAreaArg) +{ + DOMStorageEvent *This = impl_from_IDOMStorageEvent(iface); + FIXME("(%p)->(%s %x %x %s %s %s %s %p)\n", This, debugstr_w(type), can_bubble, cancelable, + debugstr_w(keyArg), debugstr_w(oldValueArg), debugstr_w(newValueArg), debugstr_w(urlArg), storageAreaArg); + return E_NOTIMPL; +} + +static const IDOMStorageEventVtbl DOMStorageEventVtbl = { + DOMStorageEvent_QueryInterface, + DOMStorageEvent_AddRef, + DOMStorageEvent_Release, + DOMStorageEvent_GetTypeInfoCount, + DOMStorageEvent_GetTypeInfo, + DOMStorageEvent_GetIDsOfNames, + DOMStorageEvent_Invoke, + DOMStorageEvent_get_key, + DOMStorageEvent_get_oldValue, + DOMStorageEvent_get_newValue, + DOMStorageEvent_get_url, + DOMStorageEvent_get_storageArea, + DOMStorageEvent_initStorageEvent +}; + +static DOMStorageEvent *DOMStorageEvent_from_DOMEvent(DOMEvent *event) +{ + return CONTAINING_RECORD(event, DOMStorageEvent, event); +} + +static void *DOMStorageEvent_query_interface(DOMEvent *event, REFIID riid) +{ + DOMStorageEvent *storage_event = DOMStorageEvent_from_DOMEvent(event); + if(IsEqualGUID(&IID_IDOMStorageEvent, riid)) + return &storage_event->IDOMStorageEvent_iface; + return NULL; +} + +static void DOMStorageEvent_destroy(DOMEvent *event) +{ + DOMStorageEvent *storage_event = DOMStorageEvent_from_DOMEvent(event); + SysFreeString(storage_event->key); + SysFreeString(storage_event->old_value); + SysFreeString(storage_event->new_value); +} + static const tid_t DOMEvent_iface_tids[] = { IDOMEvent_tid, 0 @@ -2698,6 +2860,19 @@ dispex_static_data_t DOMProgressEvent_dispex = { DOMProgressEvent_iface_tids };
+static const tid_t DOMStorageEvent_iface_tids[] = { + IDOMEvent_tid, + IDOMStorageEvent_tid, + 0 +}; + +dispex_static_data_t DOMStorageEvent_dispex = { + L"StorageEvent", + NULL, + DispDOMStorageEvent_tid, + DOMStorageEvent_iface_tids +}; + static void *event_ctor(unsigned size, dispex_static_data_t *dispex_data, void *(*query_interface)(DOMEvent*,REFIID), void (*destroy)(DOMEvent*), nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) { @@ -2799,6 +2974,15 @@ static DOMEvent *message_event_ctor(nsIDOMEvent *nsevent, eventid_t event_id, co return &message_event->event; }
+static DOMEvent *storage_event_ctor(nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +{ + DOMStorageEvent *storage_event = event_ctor(sizeof(DOMStorageEvent), &DOMStorageEvent_dispex, + DOMStorageEvent_query_interface, DOMStorageEvent_destroy, nsevent, event_id, compat_mode); + if(!storage_event) return NULL; + storage_event->IDOMStorageEvent_iface.lpVtbl = &DOMStorageEventVtbl; + return &storage_event->event; +} + static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, eventid_t event_id) { static const struct { @@ -2814,8 +2998,12 @@ static DOMEvent *alloc_event(nsIDOMEvent *nsevent, compat_mode_t compat_mode, ev DOMEvent *event; unsigned i;
- if(event_id == EVENTID_MESSAGE) - return message_event_ctor(nsevent, event_id, compat_mode); + switch(event_id) { + case EVENTID_MESSAGE: return message_event_ctor(nsevent, event_id, compat_mode); + case EVENTID_STORAGECOMMIT: + case EVENTID_STORAGE: return storage_event_ctor(nsevent, event_id, compat_mode); + default: break; + }
for(i = 0; i < ARRAY_SIZE(types_table); i++) { void *iface; @@ -2931,6 +3119,31 @@ HRESULT create_message_event(HTMLDocumentNode *doc, VARIANT *data, DOMEvent **re return S_OK; }
+HRESULT create_storage_event(HTMLDocumentNode *doc, BSTR key, BSTR old_value, BSTR new_value, + BOOL commit, DOMEvent **ret) +{ + DOMStorageEvent *storage_event; + DOMEvent *event; + HRESULT hres; + + hres = create_document_event(doc, commit ? EVENTID_STORAGECOMMIT : EVENTID_STORAGE, &event); + if(FAILED(hres)) + return hres; + storage_event = DOMStorageEvent_from_DOMEvent(event); + + if(!commit) { + if((key && !(storage_event->key = SysAllocString(key))) || + (old_value && !(storage_event->old_value = SysAllocString(old_value))) || + (new_value && !(storage_event->new_value = SysAllocString(new_value)))) { + IDOMEvent_Release(&event->IDOMEvent_iface); + return E_OUTOFMEMORY; + } + } + + *ret = event; + return S_OK; +} + static HRESULT call_disp_func(IDispatch *disp, DISPPARAMS *dp, VARIANT *retv) { IDispatchEx *dispex; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index ed11e660789..ee0c7831009 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -58,6 +58,8 @@ typedef enum { EVENTID_SCROLL, EVENTID_SELECTIONCHANGE, EVENTID_SELECTSTART, + EVENTID_STORAGE, + EVENTID_STORAGECOMMIT, EVENTID_SUBMIT, EVENTID_TIMEOUT, EVENTID_UNLOAD, @@ -112,6 +114,7 @@ HRESULT create_document_event(HTMLDocumentNode*,eventid_t,DOMEvent**) DECLSPEC_H HRESULT create_document_event_str(HTMLDocumentNode*,const WCHAR*,IDOMEvent**) DECLSPEC_HIDDEN; HRESULT create_event_from_nsevent(nsIDOMEvent*,compat_mode_t,DOMEvent**) DECLSPEC_HIDDEN; HRESULT create_message_event(HTMLDocumentNode*,VARIANT*,DOMEvent**) DECLSPEC_HIDDEN; +HRESULT create_storage_event(HTMLDocumentNode*,BSTR,BSTR,BSTR,BOOL,DOMEvent**) DECLSPEC_HIDDEN;
void init_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; void release_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/htmlstorage.c b/dlls/mshtml/htmlstorage.c index 5d56037ff04..67149e0c950 100644 --- a/dlls/mshtml/htmlstorage.c +++ b/dlls/mshtml/htmlstorage.c @@ -29,6 +29,7 @@ #include "wine/debug.h"
#include "mshtml_private.h" +#include "htmlevent.h"
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
@@ -41,6 +42,7 @@ typedef struct { LONG ref; unsigned num_props; BSTR *props; + HTMLInnerWindow *window; struct session_map_entry *session_storage; WCHAR *filename; HANDLE mutex; @@ -195,6 +197,65 @@ static inline HTMLStorage *impl_from_IHTMLStorage(IHTMLStorage *iface) return CONTAINING_RECORD(iface, HTMLStorage, IHTMLStorage_iface); }
+struct storage_event_task { + task_t header; + HTMLInnerWindow *window; + DOMEvent *event; +}; + +static void storage_event_proc(task_t *_task) +{ + struct storage_event_task *task = (struct storage_event_task*)_task; + HTMLInnerWindow *window = task->window; + DOMEvent *event = task->event; + VARIANT_BOOL cancelled; + + if(event->event_id == EVENTID_STORAGE && dispex_compat_mode(&window->event_target.dispex) >= COMPAT_MODE_IE9) { + dispatch_event(&window->event_target, event); + if(window->doc) + fire_event(&window->doc->node, L"onstorage", NULL, &cancelled); + }else if(window->doc) { + dispatch_event(&window->doc->node.event_target, event); + } +} + +static void storage_event_destr(task_t *_task) +{ + struct storage_event_task *task = (struct storage_event_task*)_task; + IDOMEvent_Release(&task->event->IDOMEvent_iface); + IHTMLWindow2_Release(&task->window->base.IHTMLWindow2_iface); +} + +/* Takes ownership of old_value */ +static HRESULT send_storage_event(HTMLStorage *storage, BSTR key, BSTR old_value, BSTR new_value) +{ + HTMLInnerWindow *window = storage->window; + BOOL local = !!storage->filename; + struct storage_event_task *task; + DOMEvent *event; + HRESULT hres; + + if(!window) { + SysFreeString(old_value); + return S_OK; + } + + hres = create_storage_event(window->doc, key, old_value, new_value, local, &event); + SysFreeString(old_value); + if(FAILED(hres)) + return hres; + + if(!(task = heap_alloc(sizeof(*task)))) { + IDOMEvent_Release(&event->IDOMEvent_iface); + return E_OUTOFMEMORY; + } + + task->event = event; + task->window = window; + IHTMLWindow2_AddRef(&task->window->base.IHTMLWindow2_iface); + return push_task(&task->header, storage_event_proc, storage_event_destr, window->task_magic); +} + static HRESULT WINAPI HTMLStorage_QueryInterface(IHTMLStorage *iface, REFIID riid, void **ppv) { HTMLStorage *This = impl_from_IHTMLStorage(iface); @@ -817,8 +878,9 @@ static HRESULT WINAPI HTMLStorage_clear(IHTMLStorage *iface) HRESULT hres = S_OK;
if(!This->filename) { + UINT num_keys = This->session_storage->num_keys; clear_session_storage(This->session_storage); - return S_OK; + return num_keys ? send_storage_event(This, NULL, NULL, NULL) : S_OK; }
WaitForSingleObject(This->mutex, INFINITE); @@ -828,6 +890,8 @@ static HRESULT WINAPI HTMLStorage_clear(IHTMLStorage *iface) hres = HRESULT_FROM_WIN32(error); } ReleaseMutex(This->mutex); + if(hres == S_OK) + hres = send_storage_event(This, NULL, NULL, NULL); return hres; }
@@ -1266,9 +1330,17 @@ HRESULT create_html_storage(HTMLInnerWindow *window, BOOL local, IHTMLStorage **
storage->IHTMLStorage_iface.lpVtbl = &HTMLStorageVtbl; storage->ref = 1; + storage->window = window; + init_dispatch(&storage->dispex, (IUnknown*)&storage->IHTMLStorage_iface, &HTMLStorage_dispex, dispex_compat_mode(&window->event_target.dispex));
*p = &storage->IHTMLStorage_iface; return S_OK; } + +void detach_html_storage(IHTMLStorage *iface) +{ + HTMLStorage *storage = impl_from_IHTMLStorage(iface); + storage->window = NULL; +} diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 00eef4d846a..ba631c9a7ef 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -299,10 +299,14 @@ static void release_inner_window(HTMLInnerWindow *This)
if(This->navigator) IOmNavigator_Release(This->navigator); - if(This->session_storage) + if(This->session_storage) { + detach_html_storage(This->session_storage); IHTMLStorage_Release(This->session_storage); - if(This->local_storage) + } + if(This->local_storage) { + detach_html_storage(This->local_storage); IHTMLStorage_Release(This->local_storage); + }
if(This->mon) IMoniker_Release(This->mon); @@ -2613,7 +2617,7 @@ HTMLWINDOW7_ONEVENT_PROPERTY_STUB(seeked) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(seeking) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(select) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(stalled) -HTMLWINDOW7_ONEVENT_PROPERTY_STUB(storage) +HTMLWINDOW7_ONEVENT_PROPERTY_IMPL(storage, EVENTID_STORAGE) HTMLWINDOW7_ONEVENT_PROPERTY_IMPL(submit, EVENTID_SUBMIT) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(suspend) HTMLWINDOW7_ONEVENT_PROPERTY_STUB(timeupdate) diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 85f34bb4a9f..18104afc10a 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -91,6 +91,7 @@ typedef struct EventTarget EventTarget; XDIID(DispDOMMessageEvent) \ XDIID(DispDOMMouseEvent) \ XDIID(DispDOMProgressEvent) \ + XDIID(DispDOMStorageEvent) \ XDIID(DispDOMUIEvent) \ XDIID(DispDOMDocumentType) \ XDIID(DispHTMLAnchorElement) \ @@ -154,6 +155,7 @@ typedef struct EventTarget EventTarget; XIID(IDOMMessageEvent) \ XIID(IDOMMouseEvent) \ XIID(IDOMProgressEvent) \ + XIID(IDOMStorageEvent) \ XIID(IDOMUIEvent) \ XIID(IDOMDocumentType) \ XIID(IDocumentEvent) \ @@ -956,6 +958,7 @@ HRESULT create_dom_implementation(HTMLDocumentNode*,IHTMLDOMImplementation**) DE void detach_dom_implementation(IHTMLDOMImplementation*) DECLSPEC_HIDDEN;
HRESULT create_html_storage(HTMLInnerWindow*,BOOL,IHTMLStorage**) DECLSPEC_HIDDEN; +void detach_html_storage(IHTMLStorage*) DECLSPEC_HIDDEN;
void HTMLDocument_Persist_Init(HTMLDocument*) DECLSPEC_HIDDEN; void HTMLDocument_OleCmd_Init(HTMLDocument*) DECLSPEC_HIDDEN;