From: Jacek Caban jacek@codeweavers.com
--- dlls/mshtml/htmlattr.c | 127 +++++++++++++++++++++++++++++++---- dlls/mshtml/htmldoc.c | 28 +++++++- dlls/mshtml/htmlelem.c | 53 ++++++++++++--- dlls/mshtml/htmlnode.c | 14 +++- dlls/mshtml/mshtml_private.h | 7 +- 5 files changed, 199 insertions(+), 30 deletions(-)
diff --git a/dlls/mshtml/htmlattr.c b/dlls/mshtml/htmlattr.c index f98356e19db..9b1544d06f0 100644 --- a/dlls/mshtml/htmlattr.c +++ b/dlls/mshtml/htmlattr.c @@ -37,7 +37,7 @@ static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *i return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface); }
-DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute, IHTMLDOMAttribute, impl_from_IHTMLDOMAttribute(iface)->dispex) +DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute, IHTMLDOMAttribute, impl_from_IHTMLDOMAttribute(iface)->node.event_target.dispex)
static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p) { @@ -45,6 +45,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BS
TRACE("(%p)->(%p)\n", This, p);
+ if(This->dom_attr) + return IHTMLDOMNode_get_nodeName(&This->node.IHTMLDOMNode_iface, p); + if(!This->elem) { if(!This->name) { FIXME("No name available\n"); @@ -65,6 +68,9 @@ static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, V
TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
+ if(This->dom_attr) + return IHTMLDOMNode_put_nodeValue(&This->node.IHTMLDOMNode_iface, v); + if(!This->elem) return VariantCopy(&This->value, &v);
@@ -78,6 +84,9 @@ static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, V
TRACE("(%p)->(%p)\n", This, p);
+ if(This->dom_attr) + return IHTMLDOMNode_get_nodeValue(&This->node.IHTMLDOMNode_iface, p); + if(!This->elem) return VariantCopy(p, &This->value);
@@ -93,6 +102,14 @@ static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, V
TRACE("(%p)->(%p)\n", This, p);
+ if(This->dom_attr) { + cpp_bool b; + nsres = nsIDOMAttr_GetSpecified(This->dom_attr, &b); + assert(nsres == NS_OK); + *p = variant_bool(b); + return S_OK; + } + if(!This->elem || !This->elem->dom_element) { *p = VARIANT_FALSE; return S_OK; @@ -131,7 +148,7 @@ static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute2(IHTMLDOMAttribute2 return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute2_iface); }
-DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute2, IHTMLDOMAttribute2, impl_from_IHTMLDOMAttribute2(iface)->dispex) +DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute2, IHTMLDOMAttribute2, impl_from_IHTMLDOMAttribute2(iface)->node.event_target.dispex)
static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p) { @@ -162,6 +179,15 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_value(IHTMLDOMAttribute2 *iface, BST
TRACE("(%p)->(%p)\n", This, p);
+ if(This->dom_attr) { + nsAString nsstr; + nsresult nsres; + + nsAString_Init(&nsstr, NULL); + nsres = nsIDOMAttr_GetValue(This->dom_attr, &nsstr); + return return_nsstr(nsres, &nsstr, p); + } + V_VT(&val) = VT_EMPTY; if(This->elem) hres = get_elem_attr_value_by_dispid(This->elem, This->dispid, &val); @@ -185,7 +211,7 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, V
TRACE("(%p)->(%p)\n", This, p);
- *p = variant_bool(This->elem && get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN); + *p = variant_bool(!This->dom_attr && This->elem && get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN); return S_OK; }
@@ -275,6 +301,9 @@ static HRESULT WINAPI HTMLDOMAttribute2_get_ownerDocument(IHTMLDOMAttribute2 *if
TRACE("(%p)->(%p)\n", This, p);
+ if(This->dom_attr) + return IHTMLDOMNode2_get_ownerDocument(&This->node.IHTMLDOMNode2_iface, p); + *p = (IDispatch*)&This->doc->IHTMLDocument2_iface; IDispatch_AddRef(*p); return S_OK; @@ -348,6 +377,16 @@ static HRESULT WINAPI HTMLDOMAttribute2_cloneNode(IHTMLDOMAttribute2 *iface, VAR
TRACE("(%p)->(%x %p)\n", This, fDeep, clonedNode);
+ if(This->dom_attr) { + IHTMLDOMNode *node; + hres = IHTMLDOMNode_cloneNode(&This->node.IHTMLDOMNode_iface, fDeep, &node); + if(SUCCEEDED(hres)) { + hres = IHTMLDOMNode_QueryInterface(node, &IID_IHTMLDOMAttribute, (void **)clonedNode); + IHTMLDOMNode_Release(node); + } + return hres; + } + if(This->elem) { hres = dispex_prop_name(&This->elem->node.event_target.dispex, This->dispid, &name); if(FAILED(hres)) @@ -407,7 +446,7 @@ static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute3(IHTMLDOMAttribute3 return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute3_iface); }
-DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute3, IHTMLDOMAttribute3, impl_from_IHTMLDOMAttribute3(iface)->dispex) +DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute3, IHTMLDOMAttribute3, impl_from_IHTMLDOMAttribute3(iface)->node.event_target.dispex)
static HRESULT WINAPI HTMLDOMAttribute3_put_nodeValue(IHTMLDOMAttribute3 *iface, VARIANT v) { @@ -460,6 +499,24 @@ static HRESULT WINAPI HTMLDOMAttribute3_get_ownerElement(IHTMLDOMAttribute3 *ifa
TRACE("(%p)->(%p)\n", This, p);
+ if(This->dom_attr) { + nsIDOMElement *dom_element; + nsresult nsres; + HRESULT hres = S_OK; + + nsres = nsIDOMAttr_GetOwnerElement(This->dom_attr, &dom_element); + assert(nsres == NS_OK); + if(dom_element) { + HTMLElement *element; + hres = get_element(dom_element, &element); + if(SUCCEEDED(hres)) + *p = &element->IHTMLElement2_iface; + }else { + *p = NULL; + } + return hres; + } + if(!This->elem) { *p = NULL; return S_OK; @@ -488,7 +545,7 @@ static const IHTMLDOMAttribute3Vtbl HTMLDOMAttribute3Vtbl = {
static inline HTMLDOMAttribute *impl_from_DispatchEx(DispatchEx *iface) { - return CONTAINING_RECORD(iface, HTMLDOMAttribute, dispex); + return CONTAINING_RECORD(iface, HTMLDOMAttribute, node.event_target.dispex); }
static void *HTMLDOMAttribute_query_interface(DispatchEx *dispex, REFIID riid) @@ -501,8 +558,10 @@ static void *HTMLDOMAttribute_query_interface(DispatchEx *dispex, REFIID riid) return &This->IHTMLDOMAttribute2_iface; if(IsEqualGUID(&IID_IHTMLDOMAttribute3, riid)) return &This->IHTMLDOMAttribute3_iface; - - return NULL; + if(!This->dom_attr) + return NULL; + /* FIXME: We shouldn't expose IHTMLDOMNode* interfaces */ + return HTMLDOMNode_query_interface(&This->node.event_target.dispex, riid); }
static void HTMLDOMAttribute_traverse(DispatchEx *dispex, nsCycleCollectionTraversalCallback *cb) @@ -573,6 +632,38 @@ HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface) return iface->lpVtbl == &HTMLDOMAttributeVtbl ? impl_from_IHTMLDOMAttribute(iface) : NULL; }
+static const cpc_entry_t HTMLDOMAttribute_cpc[] = {{NULL}}; + +static const NodeImplVtbl HTMLDOMAttributeNodeVtbl = { + .cpc_entries = HTMLDOMAttribute_cpc, +}; + +HRESULT get_attr_node(nsIDOMAttr *dom_attr, HTMLDOMAttribute **ret) +{ + HTMLDOMNode *node; + HRESULT hres; + + hres = get_node((nsIDOMNode *)dom_attr, TRUE, &node); + if(FAILED(hres)) + return hres; + assert(node->vtbl == &HTMLDOMAttributeNodeVtbl); + *ret = impl_from_DispatchEx(&node->event_target.dispex); + return S_OK; +} + +static HTMLDOMAttribute *alloc_attribute(void) +{ + HTMLDOMAttribute *ret; + + if (!(ret = calloc(1, sizeof(*ret)))) + return NULL; + + ret->IHTMLDOMAttribute_iface.lpVtbl = &HTMLDOMAttributeVtbl; + ret->IHTMLDOMAttribute2_iface.lpVtbl = &HTMLDOMAttribute2Vtbl; + ret->IHTMLDOMAttribute3_iface.lpVtbl = &HTMLDOMAttribute3Vtbl; + return ret; +} + HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, HTMLDocumentNode *doc, HTMLDOMAttribute **attr) { @@ -580,17 +671,13 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis HTMLDOMAttribute *ret; HRESULT hres;
- ret = calloc(1, sizeof(*ret)); - if(!ret) + if(!(ret = alloc_attribute())) return E_OUTOFMEMORY;
- ret->IHTMLDOMAttribute_iface.lpVtbl = &HTMLDOMAttributeVtbl; - ret->IHTMLDOMAttribute2_iface.lpVtbl = &HTMLDOMAttribute2Vtbl; - ret->IHTMLDOMAttribute3_iface.lpVtbl = &HTMLDOMAttribute3Vtbl; ret->dispid = dispid; ret->elem = elem;
- init_dispatch(&ret->dispex, &Attr_dispex, doc->script_global, + init_dispatch(&ret->node.event_target.dispex, &Attr_dispex, doc->script_global, dispex_compat_mode(&doc->script_global->event_target.dispex));
/* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */ @@ -622,3 +709,17 @@ HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dis *attr = ret; return S_OK; } + +HRESULT create_attr_node(HTMLDocumentNode *doc, nsIDOMAttr *dom_attr, HTMLDOMAttribute **ret) +{ + HTMLDOMAttribute *attr; + + if(!(attr = alloc_attribute())) + return E_OUTOFMEMORY; + + attr->node.vtbl = &HTMLDOMAttributeNodeVtbl; + HTMLDOMNode_Init(doc, &attr->node, (nsIDOMNode *)dom_attr, &Attr_dispex); + attr->dom_attr = dom_attr; /* share reference with HTMLDOMNode */ + *ret = attr; + return S_OK; +} diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 05c98e0f377..7255e8d9ec3 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -3522,13 +3522,35 @@ static HRESULT WINAPI HTMLDocument7_createElement(IHTMLDocument7 *iface, BSTR bs return IHTMLDocument2_createElement(&This->IHTMLDocument2_iface, bstrTag, newElem); }
-static HRESULT WINAPI HTMLDocument7_createAttribute(IHTMLDocument7 *iface, BSTR bstrAttrName, IHTMLDOMAttribute **ppAttribute) +static HRESULT WINAPI HTMLDocument7_createAttribute(IHTMLDocument7 *iface, BSTR name, IHTMLDOMAttribute **p) { HTMLDocumentNode *This = impl_from_IHTMLDocument7(iface); + HTMLDOMAttribute *attr; + nsIDOMAttr *nsattr; + nsAString nsstr; + nsresult nsres; + HRESULT hres; + + TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), p);
- TRACE("(%p)->(%s %p)\n", This, debugstr_w(bstrAttrName), ppAttribute); + if(!This->dom_document) { + FIXME("NULL dom_document\n"); + return E_FAIL; + }
- return IHTMLDocument5_createAttribute(&This->IHTMLDocument5_iface, bstrAttrName, ppAttribute); + nsAString_InitDepend(&nsstr, name); + nsres = nsIDOMDocument_CreateAttribute(This->dom_document, &nsstr, &nsattr); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + + hres = create_attr_node(This, nsattr, &attr); + nsIDOMAttr_Release(nsattr); + if(FAILED(hres)) + return hres; + + *p = &attr->IHTMLDOMAttribute_iface; + return S_OK; }
static HRESULT WINAPI HTMLDocument7_getElementsByClassName(IHTMLDocument7 *iface, BSTR v, IHTMLElementCollection **pel) diff --git a/dlls/mshtml/htmlelem.c b/dlls/mshtml/htmlelem.c index 22ac9fec0dc..a3b2bee3817 100644 --- a/dlls/mshtml/htmlelem.c +++ b/dlls/mshtml/htmlelem.c @@ -4442,6 +4442,31 @@ static HRESULT WINAPI HTMLElement4_setAttributeNode(IHTMLElement4 *iface, IHTMLD if(!attr) return E_INVALIDARG;
+ if(attr->dom_attr) { + HTMLDOMAttribute *prev_attr; + nsIDOMAttr *prev_nsattr; + nsresult nsres; + + if(!This->dom_element) { + FIXME("no DOM element\n"); + return E_NOTIMPL; + } + + nsres = nsIDOMElement_SetAttributeNode(This->dom_element, attr->dom_attr, &prev_nsattr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + if(!prev_nsattr) { + *ppretAttribute = NULL; + return S_OK; + } + + hres = get_attr_node(prev_nsattr, &prev_attr); + nsIDOMAttr_Release(prev_nsattr); + if(SUCCEEDED(hres)) + *ppretAttribute = &prev_attr->IHTMLDOMAttribute_iface; + return hres; + } + if(attr->elem) { WARN("Tried to set already attached attribute.\n"); return E_INVALIDARG; @@ -4752,21 +4777,29 @@ static HRESULT WINAPI HTMLElement6_removeAttribute(IHTMLElement6 *iface, BSTR st static HRESULT WINAPI HTMLElement6_getAttributeNode(IHTMLElement6 *iface, BSTR strAttributeName, IHTMLDOMAttribute2 **ppretAttribute) { HTMLElement *This = impl_from_IHTMLElement6(iface); - IHTMLDOMAttribute *attr; + HTMLDOMAttribute *attr; + nsIDOMAttr *nsattr = NULL; + nsresult nsres; HRESULT hres;
- WARN("(%p)->(%s %p) forwarding to IHTMLElement4\n", This, debugstr_w(strAttributeName), ppretAttribute); - - hres = IHTMLElement4_getAttributeNode(&This->IHTMLElement4_iface, strAttributeName, &attr); - if(FAILED(hres)) - return hres; + TRACE("(%p)->(%s %p)\n", This, debugstr_w(strAttributeName), ppretAttribute);
- if(attr) { - hres = IHTMLDOMAttribute_QueryInterface(attr, &IID_IHTMLDOMAttribute2, (void**)ppretAttribute); - IHTMLDOMAttribute_Release(attr); - }else { + if(This->dom_element) { + nsAString nsstr; + nsAString_Init(&nsstr, strAttributeName); + nsres = nsIDOMElement_GetAttributeNode(This->dom_element, &nsstr, &nsattr); + nsAString_Finish(&nsstr); + if(NS_FAILED(nsres)) + return map_nsresult(nsres); + } + if(!nsattr) { *ppretAttribute = NULL; + return S_OK; } + hres = get_attr_node(nsattr, &attr); + nsIDOMAttr_Release(nsattr); + if(SUCCEEDED(hres)) + *ppretAttribute = &attr->IHTMLDOMAttribute2_iface; return hres; }
diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c index 6b8daa00aea..0d9a5259935 100644 --- a/dlls/mshtml/htmlnode.c +++ b/dlls/mshtml/htmlnode.c @@ -1431,9 +1431,17 @@ static HRESULT create_node(HTMLDocumentNode *doc, nsIDOMNode *nsnode, HTMLDOMNod *ret = &comment->node; break; } - case ATTRIBUTE_NODE: - ERR("Called on attribute node\n"); - return E_UNEXPECTED; + case ATTRIBUTE_NODE: { + HTMLDOMAttribute *attr; + nsIDOMAttr *nsattr; + nsresult nsres; + nsres = nsIDOMNode_QueryInterface(nsnode, &IID_nsIDOMAttr, (void **)&nsattr); + assert(nsres == NS_OK); + hres = create_attr_node(doc, nsattr, &attr); + if(SUCCEEDED(hres)) + *ret = &attr->node; + return hres; + } default: { HTMLDOMNode *node;
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 5a067967a8b..0d3e5fa63a2 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -1337,11 +1337,14 @@ struct HTMLAttributeCollection { };
typedef struct { - DispatchEx dispex; + HTMLDOMNode node; /* only dispex is valid if dom_attr is NULL */ IHTMLDOMAttribute IHTMLDOMAttribute_iface; IHTMLDOMAttribute2 IHTMLDOMAttribute2_iface; IHTMLDOMAttribute3 IHTMLDOMAttribute3_iface;
+ /* Gecko attr for proper nodes, when non-NULL other fields are invalid */ + nsIDOMAttr *dom_attr; + /* value is valid only for detached attributes (when elem == NULL). */ VARIANT value; /* name must be valid for detached attributes */ @@ -1356,6 +1359,8 @@ typedef struct { HTMLDOMAttribute *unsafe_impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute*);
HRESULT HTMLDOMAttribute_Create(const WCHAR*,HTMLElement*,DISPID,HTMLDocumentNode*,HTMLDOMAttribute**); +HRESULT create_attr_node(HTMLDocumentNode *doc, nsIDOMAttr *dom_attr, HTMLDOMAttribute **ret); +HRESULT get_attr_node(nsIDOMAttr *dom_attr, HTMLDOMAttribute **ret);
HRESULT HTMLElement_Create(HTMLDocumentNode*,nsIDOMNode*,BOOL,HTMLElement**); HRESULT HTMLCommentElement_Create(HTMLDocumentNode*,nsIDOMNode*,HTMLElement**);