mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2025-08-29 02:33:58 +02:00
'expando' returns TRUE on non-builtin attributes (builtin attributes are only the builtin props, not methods), while 'specified' always returns TRUE on any non-builtin attribute as long as it has a user-defined value (e.g. for builtin methods, their slot must be non-default), which is an extension to just checking the dynamic props. Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
770 lines
23 KiB
C
770 lines
23 KiB
C
/*
|
|
* Copyright 2011 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 <stdarg.h>
|
|
|
|
#define COBJMACROS
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "ole2.h"
|
|
|
|
#include "mshtml_private.h"
|
|
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
|
|
|
|
static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface);
|
|
}
|
|
|
|
DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute, IHTMLDOMAttribute, impl_from_IHTMLDOMAttribute(iface)->node.event_target.dispex)
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
|
|
|
|
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");
|
|
return E_FAIL;
|
|
}
|
|
|
|
*p = SysAllocStringLen(This->name, SysStringLen(This->name));
|
|
return *p ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
return dispex_prop_name(&This->elem->node.event_target.dispex, This->dispid, p);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, VARIANT v)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
|
|
EXCEPINFO ei;
|
|
|
|
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);
|
|
|
|
memset(&ei, 0, sizeof(ei));
|
|
return dispex_prop_put(&This->elem->node.event_target.dispex, This->dispid, LOCALE_SYSTEM_DEFAULT, &v, &ei, NULL);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, VARIANT *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
|
|
|
|
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);
|
|
|
|
return get_elem_attr_value_by_dispid(This->elem, This->dispid, p);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, VARIANT_BOOL *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
|
|
nsAString nsname;
|
|
nsresult nsres;
|
|
cpp_bool r;
|
|
|
|
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;
|
|
}
|
|
|
|
if(!is_builtin_value(&This->elem->node.event_target.dispex, This->dispid)) {
|
|
*p = VARIANT_TRUE;
|
|
return S_OK;
|
|
}
|
|
|
|
/* FIXME: This is not exactly right, we have some attributes that don't map directly to Gecko attributes. */
|
|
nsAString_InitDepend(&nsname, dispex_builtin_prop_name(&This->elem->node.event_target.dispex, This->dispid));
|
|
nsres = nsIDOMElement_HasAttribute(This->elem->dom_element, &nsname, &r);
|
|
nsAString_Finish(&nsname);
|
|
|
|
*p = variant_bool(NS_SUCCEEDED(nsres) && r);
|
|
return S_OK;
|
|
}
|
|
|
|
static const IHTMLDOMAttributeVtbl HTMLDOMAttributeVtbl = {
|
|
HTMLDOMAttribute_QueryInterface,
|
|
HTMLDOMAttribute_AddRef,
|
|
HTMLDOMAttribute_Release,
|
|
HTMLDOMAttribute_GetTypeInfoCount,
|
|
HTMLDOMAttribute_GetTypeInfo,
|
|
HTMLDOMAttribute_GetIDsOfNames,
|
|
HTMLDOMAttribute_Invoke,
|
|
HTMLDOMAttribute_get_nodeName,
|
|
HTMLDOMAttribute_put_nodeValue,
|
|
HTMLDOMAttribute_get_nodeValue,
|
|
HTMLDOMAttribute_get_specified
|
|
};
|
|
|
|
static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute2(IHTMLDOMAttribute2 *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute2_iface);
|
|
}
|
|
|
|
DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute2, IHTMLDOMAttribute2, impl_from_IHTMLDOMAttribute2(iface)->node.event_target.dispex)
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
return IHTMLDOMAttribute_get_nodeName(&This->IHTMLDOMAttribute_iface, p);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BSTR v)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
VARIANT var;
|
|
|
|
TRACE("(%p)->(%s)\n", This, debugstr_w(v));
|
|
|
|
V_VT(&var) = VT_BSTR;
|
|
V_BSTR(&var) = v;
|
|
return IHTMLDOMAttribute_put_nodeValue(&This->IHTMLDOMAttribute_iface, var);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_value(IHTMLDOMAttribute2 *iface, BSTR *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
VARIANT val;
|
|
HRESULT hres;
|
|
|
|
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);
|
|
else
|
|
hres = VariantCopy(&val, &This->value);
|
|
if(SUCCEEDED(hres))
|
|
hres = attr_value_to_string(&val);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
assert(V_VT(&val) == VT_BSTR);
|
|
*p = V_BSTR(&val);
|
|
if(!*p && !(*p = SysAllocStringLen(NULL, 0)))
|
|
return E_OUTOFMEMORY;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
const PRUnichar *name;
|
|
nsIDOMElement *nselem;
|
|
HTMLElement *elem;
|
|
nsAString nsname;
|
|
nsresult nsres;
|
|
HRESULT hres;
|
|
DISPID id;
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
if(This->dom_attr) {
|
|
nsres = nsIDOMAttr_GetOwnerElement(This->dom_attr, &nselem);
|
|
assert(nsres == NS_OK);
|
|
if(!nselem) {
|
|
*p = VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
hres = get_element(nselem, &elem);
|
|
nsIDOMElement_Release(nselem);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
|
|
nsAString_InitDepend(&nsname, NULL);
|
|
nsres = nsIDOMAttr_GetName(This->dom_attr, &nsname);
|
|
if(NS_FAILED(nsres)) {
|
|
IHTMLElement2_Release(&elem->IHTMLElement2_iface);
|
|
return map_nsresult(nsres);
|
|
}
|
|
|
|
nsAString_GetData(&nsname, &name);
|
|
hres = dispex_get_chain_builtin_id(&elem->node.event_target.dispex, name, fdexNameCaseInsensitive, &id);
|
|
nsAString_Finish(&nsname);
|
|
if(SUCCEEDED(hres))
|
|
*p = variant_bool(dispex_builtin_is_noattr(&elem->node.event_target.dispex, id));
|
|
else if(hres == DISP_E_UNKNOWNNAME) {
|
|
*p = VARIANT_TRUE;
|
|
hres = S_OK;
|
|
}
|
|
IHTMLElement2_Release(&elem->IHTMLElement2_iface);
|
|
return hres;
|
|
}
|
|
|
|
*p = variant_bool(This->elem && !is_builtin_attribute(&This->elem->node.event_target.dispex, This->dispid));
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_nodeType(IHTMLDOMAttribute2 *iface, LONG *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = 2;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_childNodes(IHTMLDOMAttribute2 *iface, IDispatch **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_firstChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_lastChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_previousSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_nextSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_attributes(IHTMLDOMAttribute2 *iface, IDispatch **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_get_ownerDocument(IHTMLDOMAttribute2 *iface, IDispatch **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
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;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_insertBefore(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
|
|
VARIANT refChild, IHTMLDOMNode **node)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node);
|
|
|
|
/* mostly a stub, doesn't really insert anything on native either */
|
|
*node = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_replaceChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
|
|
IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
|
|
|
|
/* mostly a stub, doesn't really replace anything on native either */
|
|
*node = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_removeChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *oldChild,
|
|
IHTMLDOMNode **node)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p %p)\n", This, oldChild, node);
|
|
|
|
/* mostly a stub, doesn't really remove anything on native either */
|
|
*node = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_appendChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
|
|
IHTMLDOMNode **node)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p %p)\n", This, newChild, node);
|
|
|
|
/* mostly a stub, doesn't really append anything on native either */
|
|
*node = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_hasChildNodes(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *fChildren)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, fChildren);
|
|
|
|
*fChildren = VARIANT_FALSE;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute2_cloneNode(IHTMLDOMAttribute2 *iface, VARIANT_BOOL fDeep,
|
|
IHTMLDOMAttribute **clonedNode)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
|
|
HTMLDOMAttribute *new_attr;
|
|
HRESULT hres;
|
|
BSTR name;
|
|
|
|
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))
|
|
return hres;
|
|
hres = HTMLDOMAttribute_Create(name, NULL, 0, This->doc, &new_attr);
|
|
SysFreeString(name);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
hres = get_elem_attr_value_by_dispid(This->elem, This->dispid, &new_attr->value);
|
|
}else {
|
|
hres = HTMLDOMAttribute_Create(This->name, NULL, 0, This->doc, &new_attr);
|
|
if(FAILED(hres))
|
|
return hres;
|
|
hres = VariantCopy(&new_attr->value, &This->value);
|
|
}
|
|
|
|
if(FAILED(hres)) {
|
|
IHTMLDOMAttribute_Release(&new_attr->IHTMLDOMAttribute_iface);
|
|
return hres;
|
|
}
|
|
|
|
*clonedNode = &new_attr->IHTMLDOMAttribute_iface;
|
|
return hres;
|
|
}
|
|
|
|
static const IHTMLDOMAttribute2Vtbl HTMLDOMAttribute2Vtbl = {
|
|
HTMLDOMAttribute2_QueryInterface,
|
|
HTMLDOMAttribute2_AddRef,
|
|
HTMLDOMAttribute2_Release,
|
|
HTMLDOMAttribute2_GetTypeInfoCount,
|
|
HTMLDOMAttribute2_GetTypeInfo,
|
|
HTMLDOMAttribute2_GetIDsOfNames,
|
|
HTMLDOMAttribute2_Invoke,
|
|
HTMLDOMAttribute2_get_name,
|
|
HTMLDOMAttribute2_put_value,
|
|
HTMLDOMAttribute2_get_value,
|
|
HTMLDOMAttribute2_get_expando,
|
|
HTMLDOMAttribute2_get_nodeType,
|
|
HTMLDOMAttribute2_get_parentNode,
|
|
HTMLDOMAttribute2_get_childNodes,
|
|
HTMLDOMAttribute2_get_firstChild,
|
|
HTMLDOMAttribute2_get_lastChild,
|
|
HTMLDOMAttribute2_get_previousSibling,
|
|
HTMLDOMAttribute2_get_nextSibling,
|
|
HTMLDOMAttribute2_get_attributes,
|
|
HTMLDOMAttribute2_get_ownerDocument,
|
|
HTMLDOMAttribute2_insertBefore,
|
|
HTMLDOMAttribute2_replaceChild,
|
|
HTMLDOMAttribute2_removeChild,
|
|
HTMLDOMAttribute2_appendChild,
|
|
HTMLDOMAttribute2_hasChildNodes,
|
|
HTMLDOMAttribute2_cloneNode
|
|
};
|
|
|
|
static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute3(IHTMLDOMAttribute3 *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute3_iface);
|
|
}
|
|
|
|
DISPEX_IDISPATCH_IMPL(HTMLDOMAttribute3, IHTMLDOMAttribute3, impl_from_IHTMLDOMAttribute3(iface)->node.event_target.dispex)
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute3_put_nodeValue(IHTMLDOMAttribute3 *iface, VARIANT v)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute3(iface);
|
|
|
|
TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
|
|
|
|
return HTMLDOMAttribute_put_nodeValue(&This->IHTMLDOMAttribute_iface, v);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute3_get_nodeValue(IHTMLDOMAttribute3 *iface, VARIANT *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute3(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
return HTMLDOMAttribute_get_nodeValue(&This->IHTMLDOMAttribute_iface, p);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute3_put_value(IHTMLDOMAttribute3 *iface, BSTR v)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute3(iface);
|
|
|
|
TRACE("(%p)->(%s)\n", This, debugstr_w(v));
|
|
|
|
return HTMLDOMAttribute2_put_value(&This->IHTMLDOMAttribute2_iface, v);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute3_get_value(IHTMLDOMAttribute3 *iface, BSTR *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute3(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
return HTMLDOMAttribute2_get_value(&This->IHTMLDOMAttribute2_iface, p);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute3_get_specified(IHTMLDOMAttribute3 *iface, VARIANT_BOOL *p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute3(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, p);
|
|
|
|
return HTMLDOMAttribute_get_specified(&This->IHTMLDOMAttribute_iface, p);
|
|
}
|
|
|
|
static HRESULT WINAPI HTMLDOMAttribute3_get_ownerElement(IHTMLDOMAttribute3 *iface, IHTMLElement2 **p)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute3(iface);
|
|
|
|
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);
|
|
nsIDOMElement_Release(dom_element);
|
|
if(SUCCEEDED(hres))
|
|
*p = &element->IHTMLElement2_iface;
|
|
}else {
|
|
*p = NULL;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
if(!This->elem) {
|
|
*p = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
*p = &This->elem->IHTMLElement2_iface;
|
|
IHTMLElement2_AddRef(*p);
|
|
return S_OK;
|
|
}
|
|
|
|
static const IHTMLDOMAttribute3Vtbl HTMLDOMAttribute3Vtbl = {
|
|
HTMLDOMAttribute3_QueryInterface,
|
|
HTMLDOMAttribute3_AddRef,
|
|
HTMLDOMAttribute3_Release,
|
|
HTMLDOMAttribute3_GetTypeInfoCount,
|
|
HTMLDOMAttribute3_GetTypeInfo,
|
|
HTMLDOMAttribute3_GetIDsOfNames,
|
|
HTMLDOMAttribute3_Invoke,
|
|
HTMLDOMAttribute3_put_nodeValue,
|
|
HTMLDOMAttribute3_get_nodeValue,
|
|
HTMLDOMAttribute3_put_value,
|
|
HTMLDOMAttribute3_get_value,
|
|
HTMLDOMAttribute3_get_specified,
|
|
HTMLDOMAttribute3_get_ownerElement
|
|
};
|
|
|
|
static inline HTMLDOMAttribute *impl_from_DispatchEx(DispatchEx *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, HTMLDOMAttribute, node.event_target.dispex);
|
|
}
|
|
|
|
static void *HTMLDOMAttribute_query_interface(DispatchEx *dispex, REFIID riid)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_DispatchEx(dispex);
|
|
|
|
if(IsEqualGUID(&IID_IHTMLDOMAttribute, riid))
|
|
return &This->IHTMLDOMAttribute_iface;
|
|
if(IsEqualGUID(&IID_IHTMLDOMAttribute2, riid))
|
|
return &This->IHTMLDOMAttribute2_iface;
|
|
if(IsEqualGUID(&IID_IHTMLDOMAttribute3, riid))
|
|
return &This->IHTMLDOMAttribute3_iface;
|
|
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)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_DispatchEx(dispex);
|
|
HTMLDOMNode_traverse(&This->node.event_target.dispex, cb);
|
|
|
|
if(This->doc)
|
|
note_cc_edge((nsISupports*)&This->doc->node.IHTMLDOMNode_iface, "doc", cb);
|
|
if(This->elem)
|
|
note_cc_edge((nsISupports*)&This->elem->node.IHTMLDOMNode_iface, "elem", cb);
|
|
traverse_variant(&This->value, "value", cb);
|
|
}
|
|
|
|
static void HTMLDOMAttribute_unlink(DispatchEx *dispex)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_DispatchEx(dispex);
|
|
HTMLDOMNode_unlink(&This->node.event_target.dispex);
|
|
|
|
if(This->doc) {
|
|
HTMLDocumentNode *doc = This->doc;
|
|
This->doc = NULL;
|
|
IHTMLDOMNode_Release(&doc->node.IHTMLDOMNode_iface);
|
|
}
|
|
if(This->elem) {
|
|
HTMLElement *elem = This->elem;
|
|
This->elem = NULL;
|
|
IHTMLDOMNode_Release(&elem->node.IHTMLDOMNode_iface);
|
|
}
|
|
unlink_variant(&This->value);
|
|
}
|
|
|
|
static void HTMLDOMAttribute_destructor(DispatchEx *dispex)
|
|
{
|
|
HTMLDOMAttribute *This = impl_from_DispatchEx(dispex);
|
|
VariantClear(&This->value);
|
|
SysFreeString(This->name);
|
|
free(This);
|
|
}
|
|
|
|
static const dispex_static_data_vtbl_t HTMLDOMAttribute_dispex_vtbl = {
|
|
.query_interface = HTMLDOMAttribute_query_interface,
|
|
.destructor = HTMLDOMAttribute_destructor,
|
|
.traverse = HTMLDOMAttribute_traverse,
|
|
.unlink = HTMLDOMAttribute_unlink
|
|
};
|
|
|
|
static void HTMLDOMAttribute_init_dispex_info(dispex_data_t *info, compat_mode_t mode)
|
|
{
|
|
if(mode >= COMPAT_MODE_IE9)
|
|
HTMLDOMNode_init_dispex_info(info, mode);
|
|
if(mode >= COMPAT_MODE_IE8)
|
|
dispex_info_add_interface(info, IHTMLDOMAttribute3_tid, NULL);
|
|
}
|
|
|
|
static const tid_t HTMLDOMAttribute_iface_tids[] = {
|
|
IHTMLDOMAttribute_tid,
|
|
IHTMLDOMAttribute2_tid,
|
|
0
|
|
};
|
|
dispex_static_data_t Attr_dispex = {
|
|
.id = OBJID_Attr,
|
|
.prototype_id = OBJID_Node,
|
|
.vtbl = &HTMLDOMAttribute_dispex_vtbl,
|
|
.disp_tid = DispHTMLDOMAttribute_tid,
|
|
.iface_tids = HTMLDOMAttribute_iface_tids,
|
|
.init_info = HTMLDOMAttribute_init_dispex_info,
|
|
};
|
|
|
|
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)
|
|
{
|
|
HTMLAttributeCollection *col;
|
|
HTMLDOMAttribute *ret;
|
|
HRESULT hres;
|
|
|
|
if(!(ret = alloc_attribute()))
|
|
return E_OUTOFMEMORY;
|
|
|
|
ret->dispid = dispid;
|
|
ret->elem = elem;
|
|
|
|
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. */
|
|
if(elem) {
|
|
IHTMLDOMNode_AddRef(&elem->node.IHTMLDOMNode_iface);
|
|
|
|
hres = HTMLElement_get_attr_col(&elem->node, &col);
|
|
if(FAILED(hres)) {
|
|
IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
|
|
return hres;
|
|
}
|
|
IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface);
|
|
|
|
list_add_tail(&elem->attrs->attrs, &ret->entry);
|
|
}
|
|
|
|
/* For detached attributes we may still do most operations if we have its name available. */
|
|
if(name) {
|
|
ret->name = SysAllocString(name);
|
|
if(!ret->name) {
|
|
IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
ret->doc = doc;
|
|
IHTMLDOMNode_AddRef(&doc->node.IHTMLDOMNode_iface);
|
|
|
|
*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;
|
|
}
|