Sync with trunk r64509.
[reactos.git] / dll / win32 / mshtml / htmlattr.c
1 /*
2 * Copyright 2011 Jacek Caban for CodeWeavers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "mshtml_private.h"
20
21 static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface)
22 {
23 return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface);
24 }
25
26 static HRESULT WINAPI HTMLDOMAttribute_QueryInterface(IHTMLDOMAttribute *iface,
27 REFIID riid, void **ppv)
28 {
29 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
30
31 TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
32
33 if(IsEqualGUID(&IID_IUnknown, riid)) {
34 *ppv = &This->IHTMLDOMAttribute_iface;
35 }else if(IsEqualGUID(&IID_IHTMLDOMAttribute, riid)) {
36 *ppv = &This->IHTMLDOMAttribute_iface;
37 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
38 return *ppv ? S_OK : E_NOINTERFACE;
39 }else {
40 WARN("%s not supported\n", debugstr_mshtml_guid(riid));
41 *ppv = NULL;
42 return E_NOINTERFACE;
43 }
44
45 IUnknown_AddRef((IUnknown*)*ppv);
46 return S_OK;
47 }
48
49 static ULONG WINAPI HTMLDOMAttribute_AddRef(IHTMLDOMAttribute *iface)
50 {
51 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
52 LONG ref = InterlockedIncrement(&This->ref);
53
54 TRACE("(%p) ref=%d\n", This, ref);
55
56 return ref;
57 }
58
59 static ULONG WINAPI HTMLDOMAttribute_Release(IHTMLDOMAttribute *iface)
60 {
61 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
62 LONG ref = InterlockedDecrement(&This->ref);
63
64 TRACE("(%p) ref=%d\n", This, ref);
65
66 if(!ref) {
67 assert(!This->elem);
68 release_dispex(&This->dispex);
69 heap_free(This->name);
70 heap_free(This);
71 }
72
73 return ref;
74 }
75
76 static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfoCount(IHTMLDOMAttribute *iface, UINT *pctinfo)
77 {
78 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
79 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
80 }
81
82 static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfo(IHTMLDOMAttribute *iface, UINT iTInfo,
83 LCID lcid, ITypeInfo **ppTInfo)
84 {
85 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
86 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
87 }
88
89 static HRESULT WINAPI HTMLDOMAttribute_GetIDsOfNames(IHTMLDOMAttribute *iface, REFIID riid,
90 LPOLESTR *rgszNames, UINT cNames,
91 LCID lcid, DISPID *rgDispId)
92 {
93 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
94 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
95 lcid, rgDispId);
96 }
97
98 static HRESULT WINAPI HTMLDOMAttribute_Invoke(IHTMLDOMAttribute *iface, DISPID dispIdMember,
99 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
100 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
101 {
102 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
103 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
104 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
105 }
106
107 static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p)
108 {
109 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
110
111 TRACE("(%p)->(%p)\n", This, p);
112
113 if(!This->elem) {
114 if(!This->name) {
115 FIXME("No name available\n");
116 return E_FAIL;
117 }
118
119 *p = SysAllocString(This->name);
120 return *p ? S_OK : E_OUTOFMEMORY;
121 }
122
123 return IDispatchEx_GetMemberName(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, p);
124 }
125
126 static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, VARIANT v)
127 {
128 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
129 DISPID dispidNamed = DISPID_PROPERTYPUT;
130 DISPPARAMS dp = {&v, &dispidNamed, 1, 1};
131 EXCEPINFO ei;
132 VARIANT ret;
133
134 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
135
136 if(!This->elem) {
137 FIXME("NULL This->elem\n");
138 return E_UNEXPECTED;
139 }
140
141 memset(&ei, 0, sizeof(ei));
142
143 return IDispatchEx_InvokeEx(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
144 DISPATCH_PROPERTYPUT, &dp, &ret, &ei, NULL);
145 }
146
147 static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, VARIANT *p)
148 {
149 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
150 DISPPARAMS dp = {NULL, NULL, 0, 0};
151 EXCEPINFO ei;
152
153 TRACE("(%p)->(%p)\n", This, p);
154
155 if(!This->elem) {
156 FIXME("NULL This->elem\n");
157 return E_UNEXPECTED;
158 }
159
160 memset(&ei, 0, sizeof(ei));
161 return IDispatchEx_InvokeEx(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
162 DISPATCH_PROPERTYGET, &dp, p, &ei, NULL);
163 }
164
165 static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, VARIANT_BOOL *p)
166 {
167 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
168 nsIDOMAttr *nsattr;
169 nsAString nsname;
170 BSTR name;
171 nsresult nsres;
172 HRESULT hres;
173
174 TRACE("(%p)->(%p)\n", This, p);
175
176 if(!This->elem || !This->elem->nselem) {
177 FIXME("NULL This->elem\n");
178 return E_UNEXPECTED;
179 }
180
181 if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) {
182 *p = VARIANT_TRUE;
183 return S_OK;
184 }
185
186 hres = IDispatchEx_GetMemberName(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, &name);
187 if(FAILED(hres))
188 return hres;
189
190 /* FIXME: This is not exactly right, we have some attributes that don't map directly to Gecko attributes. */
191 nsAString_InitDepend(&nsname, name);
192 nsres = nsIDOMHTMLElement_GetAttributeNode(This->elem->nselem, &nsname, &nsattr);
193 nsAString_Finish(&nsname);
194 SysFreeString(name);
195 if(NS_FAILED(nsres))
196 return E_FAIL;
197
198 /* If the Gecko attribute node can be found, we know that the attribute is specified.
199 There is no point in calling GetSpecified */
200 if(nsattr) {
201 nsIDOMAttr_Release(nsattr);
202 *p = VARIANT_TRUE;
203 }else {
204 *p = VARIANT_FALSE;
205 }
206 return S_OK;
207 }
208
209 static const IHTMLDOMAttributeVtbl HTMLDOMAttributeVtbl = {
210 HTMLDOMAttribute_QueryInterface,
211 HTMLDOMAttribute_AddRef,
212 HTMLDOMAttribute_Release,
213 HTMLDOMAttribute_GetTypeInfoCount,
214 HTMLDOMAttribute_GetTypeInfo,
215 HTMLDOMAttribute_GetIDsOfNames,
216 HTMLDOMAttribute_Invoke,
217 HTMLDOMAttribute_get_nodeName,
218 HTMLDOMAttribute_put_nodeValue,
219 HTMLDOMAttribute_get_nodeValue,
220 HTMLDOMAttribute_get_specified
221 };
222
223 static const tid_t HTMLDOMAttribute_iface_tids[] = {
224 IHTMLDOMAttribute_tid,
225 0
226 };
227 static dispex_static_data_t HTMLDOMAttribute_dispex = {
228 NULL,
229 DispHTMLDOMAttribute_tid,
230 0,
231 HTMLDOMAttribute_iface_tids
232 };
233
234 HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, HTMLDOMAttribute **attr)
235 {
236 HTMLAttributeCollection *col;
237 HTMLDOMAttribute *ret;
238 HRESULT hres;
239
240 ret = heap_alloc_zero(sizeof(*ret));
241 if(!ret)
242 return E_OUTOFMEMORY;
243
244 ret->IHTMLDOMAttribute_iface.lpVtbl = &HTMLDOMAttributeVtbl;
245 ret->ref = 1;
246 ret->dispid = dispid;
247 ret->elem = elem;
248
249 init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface,
250 &HTMLDOMAttribute_dispex);
251
252 /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */
253 if(elem) {
254 hres = HTMLElement_get_attr_col(&elem->node, &col);
255 if(FAILED(hres)) {
256 IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
257 return hres;
258 }
259 IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface);
260
261 list_add_tail(&elem->attrs->attrs, &ret->entry);
262 }
263
264 /* For detached attributes we may still do most operations if we have its name available. */
265 if(name) {
266 ret->name = heap_strdupW(name);
267 if(!ret->name) {
268 IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
269 return E_OUTOFMEMORY;
270 }
271 }
272
273 *attr = ret;
274 return S_OK;
275 }