Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/mshtml/htmlelem.c | 88 ++++++++++++++++++++++++++++ dlls/mshtml/mshtml_private.h | 2 + dlls/mshtml/mshtml_private_iface.idl | 13 ++++ dlls/mshtml/tests/documentmode.js | 1 + 4 files changed, 104 insertions(+)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index b9677ec867a..961e4e79e08 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6065,6 +6065,8 @@ HRESULT HTMLElement_QI(HTMLDOMNode *iface, REFIID riid, void **ppv) *ppv = &This->IProvideMultipleClassInfo_iface; }else if(IsEqualGUID(&IID_IProvideMultipleClassInfo, riid)) { *ppv = &This->IProvideMultipleClassInfo_iface; + }else if(IsEqualGUID(&IID_IWineHTMLElementPrivate, riid)) { + *ppv = &This->IWineHTMLElementPrivate_iface; }else { return HTMLDOMNode_QI(&This->node, riid, ppv); } @@ -6366,7 +6368,10 @@ void HTMLElement_init_dispex_info(dispex_data_t *info, compat_mode_t mode) }
if(mode >= COMPAT_MODE_IE10) + { dispex_info_add_interface(info, IHTMLElement7_tid, NULL); + dispex_info_add_interface(info, IWineHTMLElementPrivate_tid, NULL); + } }
static const tid_t HTMLElement_iface_tids[] = { @@ -6390,6 +6395,88 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = { HTMLElement_set_current_event };
+static inline HTMLElement *impl_from_IWineHTMLElementPrivateVtbl(IWineHTMLElementPrivate *iface) +{ + return CONTAINING_RECORD(iface, HTMLElement, IWineHTMLElementPrivate_iface); +} + +static HRESULT WINAPI htmlelement_private_QueryInterface(IWineHTMLElementPrivate *iface, + REFIID riid, void **ppv) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return IHTMLElement_QueryInterface(&This->IHTMLElement_iface, riid, ppv); +} + +static ULONG WINAPI htmlelement_private_AddRef(IWineHTMLElementPrivate *iface) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return IHTMLElement_AddRef(&This->IHTMLElement_iface); +} + +static ULONG WINAPI htmlelement_private_Release(IWineHTMLElementPrivate *iface) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return IHTMLElement_Release(&This->IHTMLElement_iface); +} + +static HRESULT WINAPI htmlelement_private_GetTypeInfoCount(IWineHTMLElementPrivate *iface, UINT *pctinfo) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return HTMLElement_GetTypeInfoCount(&This->IHTMLElement_iface, pctinfo); +} + +static HRESULT WINAPI htmlelement_private_GetTypeInfo(IWineHTMLElementPrivate *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return HTMLElement_GetTypeInfo(&This->IHTMLElement_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI htmlelement_private_GetIDsOfNames(IWineHTMLElementPrivate *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return HTMLElement_GetIDsOfNames(&This->IHTMLElement_iface, riid, rgszNames, cNames, lcid, + rgDispId); +} + +static HRESULT WINAPI htmlelement_private_Invoke(IWineHTMLElementPrivate *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface); + + return HTMLElement_Invoke(&This->IHTMLElement_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI htmlelement_private_get_classList(IWineHTMLElementPrivate *iface, IDispatch **class_list) +{ + FIXME("iface %p, class_list %p stub.\n", iface, class_list); + + *class_list = NULL; + + return S_OK; +} + +static const IWineHTMLElementPrivateVtbl WineHTMLElementPrivateVtbl = { + htmlelement_private_QueryInterface, + htmlelement_private_AddRef, + htmlelement_private_Release, + htmlelement_private_GetTypeInfoCount, + htmlelement_private_GetTypeInfo, + htmlelement_private_GetIDsOfNames, + htmlelement_private_Invoke, + htmlelement_private_get_classList, +}; + static dispex_static_data_t HTMLElement_dispex = { &HTMLElement_event_target_vtbl.dispex_vtbl, DispHTMLUnknownElement_tid, @@ -6409,6 +6496,7 @@ void HTMLElement_Init(HTMLElement *This, HTMLDocumentNode *doc, nsIDOMElement *n This->IElementSelector_iface.lpVtbl = &ElementSelectorVtbl; This->IElementTraversal_iface.lpVtbl = &ElementTraversalVtbl; This->IProvideMultipleClassInfo_iface.lpVtbl = &ProvideMultipleClassInfoVtbl; + This->IWineHTMLElementPrivate_iface.lpVtbl = &WineHTMLElementPrivateVtbl;
if(dispex_data && !dispex_data->vtbl) dispex_data->vtbl = &HTMLElement_event_target_vtbl.dispex_vtbl; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e2c1f221372..56bef40b4d0 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -273,6 +273,7 @@ typedef struct EventTarget EventTarget; XIID(ISVGTextContentElement)
#define PRIVATE_TID_LIST \ + XIID(IWineHTMLElementPrivate) \ XIID(IWineHTMLWindowPrivate) \ XIID(IWineMSHTMLConsole)
@@ -828,6 +829,7 @@ typedef struct { IElementSelector IElementSelector_iface; IElementTraversal IElementTraversal_iface; IProvideMultipleClassInfo IProvideMultipleClassInfo_iface; + IWineHTMLElementPrivate IWineHTMLElementPrivate_iface;
nsIDOMElement *dom_element; /* NULL for legacy comments represented as HTML elements */ nsIDOMHTMLElement *html_element; /* NULL for non-HTML elements (like SVG elements) */ diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 6c5c5db991f..9ca7e0d7421 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -89,4 +89,17 @@ interface IWineHTMLWindowPrivate : IDispatch HRESULT console([retval, out] IDispatch **console); }
+[ + odl, + oleautomation, + dual, + hidden, + uuid(465908fd-f394-489f-b7a3-4c00fbbe9eec) +] +interface IWineHTMLElementPrivate : IDispatch +{ + [propget, id(1)] + HRESULT classList([retval, out] IDispatch **class_list); +} + } /* library MSHTML_private */ diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 859e1fe53db..c20f6ee18df 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -57,6 +57,7 @@ sync_test("elem_props", function() { test_exposed("sheet", v >= 9); test_exposed("readyState", v < 11); test_exposed("styleSheet", v < 11); + test_exposed("classList", v >= 10); });
sync_test("doc_props", function() {
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/mshtml/htmlelem.c | 143 ++++++++++++++++++++++++++- dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/mshtml_private_iface.idl | 11 +++ dlls/mshtml/tests/dom.js | 5 + 4 files changed, 157 insertions(+), 3 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 961e4e79e08..5bb3f1eaf15 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6395,6 +6395,142 @@ static event_target_vtbl_t HTMLElement_event_target_vtbl = { HTMLElement_set_current_event };
+struct token_list { + DispatchEx dispex; + IWineDOMTokenList IWineDOMTokenList_iface; + IHTMLElement *element; + + LONG ref; +}; + +static inline struct token_list *impl_from_IWineDOMTokenList(IWineDOMTokenList *iface) +{ + return CONTAINING_RECORD(iface, struct token_list, IWineDOMTokenList_iface); +} + +static HRESULT WINAPI token_list_QueryInterface(IWineDOMTokenList *iface, REFIID riid, void **ppv) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + + TRACE("(%p)->(%s %p)\n", token_list, debugstr_mshtml_guid(riid), ppv); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + *ppv = &token_list->IWineDOMTokenList_iface; + }else if(IsEqualGUID(&IID_IWineDOMTokenList, riid)) { + *ppv = &token_list->IWineDOMTokenList_iface; + }else if(dispex_query_interface(&token_list->dispex, riid, ppv)) { + return *ppv ? S_OK : E_NOINTERFACE; + }else { + WARN("(%p)->(%s %p)\n", token_list, debugstr_mshtml_guid(riid), ppv); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI token_list_AddRef(IWineDOMTokenList *iface) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + LONG ref = InterlockedIncrement(&token_list->ref); + + TRACE("(%p) ref=%d\n", token_list, ref); + + return ref; +} + +static ULONG WINAPI token_list_Release(IWineDOMTokenList *iface) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + LONG ref = InterlockedDecrement(&token_list->ref); + + TRACE("(%p) ref=%d\n", token_list, ref); + + if(!ref) { + IHTMLElement_Release(token_list->element); + release_dispex(&token_list->dispex); + heap_free(token_list); + } + + return ref; +} + +static HRESULT WINAPI token_list_GetTypeInfoCount(IWineDOMTokenList *iface, UINT *pctinfo) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + FIXME("(%p)->(%p)\n", token_list, pctinfo); + return E_NOTIMPL; +} + +static HRESULT WINAPI token_list_GetTypeInfo(IWineDOMTokenList *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + + return IDispatchEx_GetTypeInfo(&token_list->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI token_list_GetIDsOfNames(IWineDOMTokenList *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + + return IDispatchEx_GetIDsOfNames(&token_list->dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI token_list_Invoke(IWineDOMTokenList *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + + return IDispatchEx_Invoke(&token_list->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, wFlags, + pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { + token_list_QueryInterface, + token_list_AddRef, + token_list_Release, + token_list_GetTypeInfoCount, + token_list_GetTypeInfo, + token_list_GetIDsOfNames, + token_list_Invoke, +}; + +static const tid_t token_list_iface_tids[] = { + IWineDOMTokenList_tid, + 0 +}; +static dispex_static_data_t token_list_dispex = { + NULL, + IWineDOMTokenList_tid, + token_list_iface_tids +}; + +static HRESULT create_token_list(compat_mode_t compat_mode, IHTMLElement *element, IWineDOMTokenList **ret) +{ + struct token_list *obj; + + obj = heap_alloc_zero(sizeof(*obj)); + if(!obj) + { + ERR("No memory.\n"); + return E_OUTOFMEMORY; + } + + obj->IWineDOMTokenList_iface.lpVtbl = &WineDOMTokenListVtbl; + obj->ref = 1; + init_dispatch(&obj->dispex, (IUnknown*)&obj->IWineDOMTokenList_iface, &token_list_dispex, compat_mode); + IHTMLElement_AddRef(element); + obj->element = element; + + *ret = &obj->IWineDOMTokenList_iface; + return S_OK; +} + static inline HTMLElement *impl_from_IWineHTMLElementPrivateVtbl(IWineHTMLElementPrivate *iface) { return CONTAINING_RECORD(iface, HTMLElement, IWineHTMLElementPrivate_iface); @@ -6459,11 +6595,12 @@ static HRESULT WINAPI htmlelement_private_Invoke(IWineHTMLElementPrivate *iface,
static HRESULT WINAPI htmlelement_private_get_classList(IWineHTMLElementPrivate *iface, IDispatch **class_list) { - FIXME("iface %p, class_list %p stub.\n", iface, class_list); + HTMLElement *This = impl_from_IWineHTMLElementPrivateVtbl(iface);
- *class_list = NULL; + TRACE("iface %p, class_list %p.\n", iface, class_list);
- return S_OK; + return create_token_list(dispex_compat_mode(&This->node.event_target.dispex), &This->IHTMLElement_iface, + (IWineDOMTokenList **)class_list); }
static const IWineHTMLElementPrivateVtbl WineHTMLElementPrivateVtbl = { diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 56bef40b4d0..c1e7e78253d 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -273,6 +273,7 @@ typedef struct EventTarget EventTarget; XIID(ISVGTextContentElement)
#define PRIVATE_TID_LIST \ + XIID(IWineDOMTokenList) \ XIID(IWineHTMLElementPrivate) \ XIID(IWineHTMLWindowPrivate) \ XIID(IWineMSHTMLConsole) diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 9ca7e0d7421..1764b0a8c9d 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -102,4 +102,15 @@ interface IWineHTMLElementPrivate : IDispatch HRESULT classList([retval, out] IDispatch **class_list); }
+[ + odl, + oleautomation, + dual, + hidden, + uuid(08ef0edd-5fb8-4178-a2f0-9f686e00441b) +] +interface IWineDOMTokenList : IDispatch +{ +} + } /* library MSHTML_private */ diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index a2c70540eba..f54cb0f7088 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -508,3 +508,8 @@ sync_test("hasAttribute", function() { r = elem.hasAttribute("attr"); ok(r === false, "hasAttribute(attr) returned " + r); }); + +sync_test("classList", function() { + var elem = document.createElement("div"); + var classList = elem.classList; +});
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/mshtml/htmlelem.c | 127 +++++++++++++++++++++++++++ dlls/mshtml/mshtml_private_iface.idl | 2 + dlls/mshtml/tests/dom.js | 50 +++++++++++ 3 files changed, 179 insertions(+)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 5bb3f1eaf15..b5b0daa2539 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6490,6 +6490,132 @@ static HRESULT WINAPI token_list_Invoke(IWineDOMTokenList *iface, DISPID dispIdM pDispParams, pVarResult, pExcepInfo, puArgErr); }
+static const WCHAR *find_token(const WCHAR *list, const WCHAR *token, unsigned int token_len) +{ + const WCHAR *ptr, *next; + + if (!list || !token) + return NULL; + + ptr = list; + while (*ptr) + { + while (iswspace(*ptr)) + ++ptr; + if (!*ptr) + break; + next = ptr + 1; + while (*next && !iswspace(*next)) + ++next; + + if (next - ptr == token_len && !wcsncmp(ptr, token, token_len)) + return ptr; + ptr = next; + } + return NULL; +} + +static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_array) +{ + struct token_list *token_list = impl_from_IWineDOMTokenList(iface); + unsigned int i, len, old_len, new_len; + WCHAR *token, *old, *new; + VARIANT *var, tmp; + HRESULT hr; + + TRACE("iface %p, token_array %p.\n", iface, token_array); + + hr = SafeArrayAccessData(token_array, (void**)&var); + if(FAILED(hr)) { + WARN("SafeArrayAccessData failed: %08x\n", hr); + return hr; + } + + if (!token_array->rgsabound[0].cElements) + { + FIXME("No arguments given."); + SafeArrayUnaccessData(token_array); + return E_INVALIDARG; + } + + if(V_VT(var) != VT_BSTR) + { + hr = VariantChangeTypeEx(&tmp, var, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR); + if(FAILED(hr)) + { + WARN("Could not convert %s to string\n", debugstr_variant(var)); + SafeArrayUnaccessData(token_array); + return hr; + } + token = V_BSTR(&tmp); + } + else + { + token = V_BSTR(var); + } + + if (token_array->rgsabound[0].cElements > 1) + WARN("%u tokens given, using first one only.\n", token_array->rgsabound[0].cElements); + + len = lstrlenW(token); + if (!len) + { + WARN("Empty token.\n"); + hr = E_INVALIDARG; + goto done; + } + + for (i = 0; i < len; ++i) + if (iswspace(token[i])) + { + WARN("Token has spaces.\n"); + hr = E_INVALIDARG; + goto done; + } + + if (FAILED(hr = IHTMLElement_get_className(token_list->element, &old))) + goto done; + + TRACE("old %s.\n", debugstr_w(old)); + + if (find_token(old, token, len)) + { + SysFreeString(old); + hr = S_OK; + goto done; + } + + old_len = old ? lstrlenW(old) : 0; + new_len = old_len + len + !!old_len; + + if (!(new = heap_alloc(sizeof(*new) * (new_len + 1)))) + { + ERR("No memory.\n"); + SysFreeString(old); + hr = E_OUTOFMEMORY; + goto done; + } + + memcpy(new, old, sizeof(*new) * old_len); + if (old_len) + new[old_len++]= L' '; + memcpy(new + old_len, token, sizeof(*new) * len); + new[old_len + len] = 0; + + SysFreeString(old); + + TRACE("new %s.\n", debugstr_w(new)); + + hr = IHTMLElement_put_className(token_list->element, new); + heap_free(new); +done: + SafeArrayUnaccessData(token_array); + if(V_VT(var) != VT_BSTR) + VariantClear(&tmp); + + return hr; +} + static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_QueryInterface, token_list_AddRef, @@ -6498,6 +6624,7 @@ static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_GetTypeInfo, token_list_GetIDsOfNames, token_list_Invoke, + token_list_add, };
static const tid_t token_list_iface_tids[] = { diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 1764b0a8c9d..b50d2f9502b 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -111,6 +111,8 @@ interface IWineHTMLElementPrivate : IDispatch ] interface IWineDOMTokenList : IDispatch { + [vararg, id(1)] + HRESULT add([in] SAFEARRAY(VARIANT) token); }
} /* library MSHTML_private */ diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index f54cb0f7088..ae6d49da26c 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -512,4 +512,54 @@ sync_test("hasAttribute", function() { sync_test("classList", function() { var elem = document.createElement("div"); var classList = elem.classList; + + classList.add("a"); + ok(elem.className === "a", "Expected className 'a', got " + elem.className); + + classList.add("b"); + ok(elem.className === "a b", "Expected className 'a b', got " + elem.className); + + classList.add("c", "d"); + ok(elem.className === "a b c", "Expected className 'a b c', got " + elem.className); + + classList.add(4); + ok(elem.className === "a b c 4", "Expected className 'a b c 4', got " + elem.className); + + classList.add("c", "d"); + ok(elem.className === "a b c 4", "(2) Expected className 'a b c 4', got " + elem.className); + + var exception = false + + try + { + classList.add(); + } + catch(e) + { + exception = true; + } + ok(exception && elem.className === "a b c 4", "Expected exception, className 'a b c 4', got exception " + + exception + ", className" + elem.className); + + exception = false + try + { + classList.add(""); + } + catch(e) + { + exception = true; + } + ok(exception, "Expected exception for classList.add("")"); + + exception = false + try + { + classList.add("e f"); + } + catch(e) + { + exception = true; + } + ok(exception, "Expected exception for classList.add("e f")"); });
On 7/19/21 11:55 AM, Paul Gofman wrote:
- TRACE("new %s.\n", debugstr_w(new));
- hr = IHTMLElement_put_className(token_list->element, new);
IHTMLElement_put_className takes BSTR as an argument.
static const tid_t token_list_iface_tids[] = { diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index 1764b0a8c9d..b50d2f9502b 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -111,6 +111,8 @@ interface IWineHTMLElementPrivate : IDispatch ] interface IWineDOMTokenList : IDispatch {
- [vararg, id(1)]
- HRESULT add([in] SAFEARRAY(VARIANT) token); }
This should probably just take a single BSTR argument instead. The behaviour that you observe with multiple arguments should probably be handled on dispatch level instead. A quick testing shows that extra argument are generally accepted by any JavaScript function call. This is consistent with how builtin JavaScript functions work. I think it wasn't the case for old IEs, but it looks like recent versions accept it for all compatibility modes.
Thanks,
Jacek
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94207
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w8adm (32 bit report) ===
mshtml: htmldoc.c:3084: Test failed: Incorrect error code: -2146697211 htmldoc.c:3089: Test failed: Page address: L"http://test.winehq.org/tests/winehq_snapshot/" htmldoc.c:5861: Test failed: expected OnChanged_1012 htmldoc.c:5862: Test failed: expected Exec_HTTPEQUIV htmldoc.c:5864: Test failed: expected Exec_SETTITLE htmldoc.c:5905: Test failed: expected FireNavigateComplete2
Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/mshtml/htmlelem.c | 55 ++++++++++++++++++++++++---- dlls/mshtml/mshtml_private_iface.idl | 2 + dlls/mshtml/tests/dom.js | 43 ++++++++++++++++++++++ 3 files changed, 92 insertions(+), 8 deletions(-)
diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index b5b0daa2539..4506f170616 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -6515,11 +6515,12 @@ static const WCHAR *find_token(const WCHAR *list, const WCHAR *token, unsigned i return NULL; }
-static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_array) +static HRESULT WINAPI token_list_add_remove(IWineDOMTokenList *iface, SAFEARRAY *token_array, BOOL remove) { struct token_list *token_list = impl_from_IWineDOMTokenList(iface); unsigned int i, len, old_len, new_len; WCHAR *token, *old, *new; + const WCHAR *old_pos; VARIANT *var, tmp; HRESULT hr;
@@ -6578,7 +6579,8 @@ static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_
TRACE("old %s.\n", debugstr_w(old));
- if (find_token(old, token, len)) + if (((old_pos = find_token(old, token, len)) && !remove) + || (!old_pos && remove)) { SysFreeString(old); hr = S_OK; @@ -6586,7 +6588,25 @@ static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_ }
old_len = old ? lstrlenW(old) : 0; - new_len = old_len + len + !!old_len; + if (remove) + { + while (old_pos != old && iswspace(old_pos[-1])) + { + --old_pos; + ++len; + } + while (iswspace(old_pos[len])) + ++len; + + if (old_pos != old && old_pos[len]) + --len; + + new_len = old_len - len; + } + else + { + new_len = old_len + len + !!old_len; + }
if (!(new = heap_alloc(sizeof(*new) * (new_len + 1)))) { @@ -6596,11 +6616,19 @@ static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_ goto done; }
- memcpy(new, old, sizeof(*new) * old_len); - if (old_len) - new[old_len++]= L' '; - memcpy(new + old_len, token, sizeof(*new) * len); - new[old_len + len] = 0; + if (remove) + { + memcpy(new, old, sizeof(*new) * (old_pos - old)); + memcpy(new + (old_pos - old), old_pos + len, sizeof(*new) * (old_len - (old_pos - old) - len + 1)); + } + else + { + memcpy(new, old, sizeof(*new) * old_len); + if (old_len) + new[old_len++]= L' '; + memcpy(new + old_len, token, sizeof(*new) * len); + new[old_len + len] = 0; + }
SysFreeString(old);
@@ -6616,6 +6644,16 @@ done: return hr; }
+static HRESULT WINAPI token_list_add(IWineDOMTokenList *iface, SAFEARRAY *token_array) +{ + return token_list_add_remove(iface, token_array, FALSE); +} + +static HRESULT WINAPI token_list_remove(IWineDOMTokenList *iface, SAFEARRAY *token_array) +{ + return token_list_add_remove(iface, token_array, TRUE); +} + static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_QueryInterface, token_list_AddRef, @@ -6625,6 +6663,7 @@ static const IWineDOMTokenListVtbl WineDOMTokenListVtbl = { token_list_GetIDsOfNames, token_list_Invoke, token_list_add, + token_list_remove, };
static const tid_t token_list_iface_tids[] = { diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index b50d2f9502b..7dc4928aab8 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -113,6 +113,8 @@ interface IWineDOMTokenList : IDispatch { [vararg, id(1)] HRESULT add([in] SAFEARRAY(VARIANT) token); + [vararg, id(2)] + HRESULT remove([in] SAFEARRAY(VARIANT) token); }
} /* library MSHTML_private */ diff --git a/dlls/mshtml/tests/dom.js b/dlls/mshtml/tests/dom.js index ae6d49da26c..f3fe245d250 100644 --- a/dlls/mshtml/tests/dom.js +++ b/dlls/mshtml/tests/dom.js @@ -562,4 +562,47 @@ sync_test("classList", function() { exception = true; } ok(exception, "Expected exception for classList.add("e f")"); + + classList.remove("e"); + ok(elem.className === "a b c 4", "remove: expected className 'a b c 4', got " + elem.className); + + exception = false + try + { + classList.remove("e f"); + } + catch(e) + { + exception = true; + } + ok(exception, "remove: expected exception for classList.remove("e f")"); + + exception = false + try + { + classList.remove(""); + } + catch(e) + { + exception = true; + } + ok(exception, "remove: expected exception for classList.remove("")"); + + classList.remove("d"); + ok(elem.className === "a b c 4", "remove: expected className 'a b c 4', got " + elem.className); + + classList.remove("c", 4); + ok(elem.className === "a b 4", "remove: expected className 'a b 4', got " + elem.className); + + classList.remove(4); + ok(elem.className === "a b", "remove: expected className 'a b', got " + elem.className); + + classList.remove('a'); + ok(elem.className === "b", "remove: expected className 'b', got " + elem.className); + + classList.remove("a"); + ok(elem.className === "b", "remove (2): expected className 'b', got " + elem.className); + + classList.remove("b"); + ok(elem.className === "", "remove: expected className '', got " + elem.className); });
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94208
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: htmldoc.c:3084: Test failed: Incorrect error code: -2146697211 htmldoc.c:3089: Test failed: Page address: L"http://test.winehq.org/tests/winehq_snapshot/" htmldoc.c:5861: Test failed: expected OnChanged_1012 htmldoc.c:5862: Test failed: expected Exec_HTTPEQUIV htmldoc.c:5864: Test failed: expected Exec_SETTITLE htmldoc.c:5905: Test failed: expected FireNavigateComplete2
=== debiant2 (32 bit Hindi:India report) ===
mshtml: script.c:624: Test failed: L"/index.html?dom.js:classList: Got exception "
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94205
Your paranoid android.
=== w8adm (32 bit report) ===
mshtml: events.c:1089: Test failed: unexpected call img_onerror events: Timeout
=== w1064_tsign (64 bit report) ===
mshtml: htmldoc.c:2541: Test failed: unexpected call UpdateUI htmldoc.c:2853: Test failed: unexpected call Exec_UPDATECOMMANDS htmldoc.c:350: Test failed: expected Exec_SETTITLE htmldoc.c:2859: Test failed: unexpected call Exec_SETTITLE