Reactos
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
21static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface)
22{
23 return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface);
24}
25
26static 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(IsEqualGUID(&IID_IHTMLDOMAttribute2, riid)) {
38 *ppv = &This->IHTMLDOMAttribute2_iface;
39 }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
40 return *ppv ? S_OK : E_NOINTERFACE;
41 }else {
42 WARN("%s not supported\n", debugstr_mshtml_guid(riid));
43 *ppv = NULL;
44 return E_NOINTERFACE;
45 }
46
47 IUnknown_AddRef((IUnknown*)*ppv);
48 return S_OK;
49}
50
51static ULONG WINAPI HTMLDOMAttribute_AddRef(IHTMLDOMAttribute *iface)
52{
53 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
54 LONG ref = InterlockedIncrement(&This->ref);
55
56 TRACE("(%p) ref=%d\n", This, ref);
57
58 return ref;
59}
60
61static ULONG WINAPI HTMLDOMAttribute_Release(IHTMLDOMAttribute *iface)
62{
63 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
64 LONG ref = InterlockedDecrement(&This->ref);
65
66 TRACE("(%p) ref=%d\n", This, ref);
67
68 if(!ref) {
69 assert(!This->elem);
70 release_dispex(&This->dispex);
71 heap_free(This->name);
72 heap_free(This);
73 }
74
75 return ref;
76}
77
78static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfoCount(IHTMLDOMAttribute *iface, UINT *pctinfo)
79{
80 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
81 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
82}
83
84static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfo(IHTMLDOMAttribute *iface, UINT iTInfo,
85 LCID lcid, ITypeInfo **ppTInfo)
86{
87 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
88 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
89}
90
91static HRESULT WINAPI HTMLDOMAttribute_GetIDsOfNames(IHTMLDOMAttribute *iface, REFIID riid,
92 LPOLESTR *rgszNames, UINT cNames,
93 LCID lcid, DISPID *rgDispId)
94{
95 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
96 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
97 lcid, rgDispId);
98}
99
100static HRESULT WINAPI HTMLDOMAttribute_Invoke(IHTMLDOMAttribute *iface, DISPID dispIdMember,
101 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
102 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
103{
104 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
105 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
106 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
107}
108
109static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p)
110{
111 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
112
113 TRACE("(%p)->(%p)\n", This, p);
114
115 if(!This->elem) {
116 if(!This->name) {
117 FIXME("No name available\n");
118 return E_FAIL;
119 }
120
121 *p = SysAllocString(This->name);
122 return *p ? S_OK : E_OUTOFMEMORY;
123 }
124
125 return IDispatchEx_GetMemberName(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, p);
126}
127
128static HRESULT WINAPI HTMLDOMAttribute_put_nodeValue(IHTMLDOMAttribute *iface, VARIANT v)
129{
130 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
131 DISPID dispidNamed = DISPID_PROPERTYPUT;
132 DISPPARAMS dp = {&v, &dispidNamed, 1, 1};
133 EXCEPINFO ei;
134 VARIANT ret;
135
136 TRACE("(%p)->(%s)\n", This, debugstr_variant(&v));
137
138 if(!This->elem) {
139 FIXME("NULL This->elem\n");
140 return E_UNEXPECTED;
141 }
142
143 memset(&ei, 0, sizeof(ei));
144
145 return IDispatchEx_InvokeEx(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
146 DISPATCH_PROPERTYPUT, &dp, &ret, &ei, NULL);
147}
148
149static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, VARIANT *p)
150{
151 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
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 return get_elem_attr_value_by_dispid(This->elem, This->dispid, 0, p);
161}
162
163static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, VARIANT_BOOL *p)
164{
165 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
166 nsIDOMAttr *nsattr;
167 nsAString nsname;
168 BSTR name;
169 nsresult nsres;
170 HRESULT hres;
171
172 TRACE("(%p)->(%p)\n", This, p);
173
174 if(!This->elem || !This->elem->nselem) {
175 FIXME("NULL This->elem\n");
176 return E_UNEXPECTED;
177 }
178
179 if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) {
180 *p = VARIANT_TRUE;
181 return S_OK;
182 }
183
184 hres = IDispatchEx_GetMemberName(&This->elem->node.event_target.dispex.IDispatchEx_iface, This->dispid, &name);
185 if(FAILED(hres))
186 return hres;
187
188 /* FIXME: This is not exactly right, we have some attributes that don't map directly to Gecko attributes. */
189 nsAString_InitDepend(&nsname, name);
190 nsres = nsIDOMHTMLElement_GetAttributeNode(This->elem->nselem, &nsname, &nsattr);
191 nsAString_Finish(&nsname);
192 SysFreeString(name);
193 if(NS_FAILED(nsres))
194 return E_FAIL;
195
196 /* If the Gecko attribute node can be found, we know that the attribute is specified.
197 There is no point in calling GetSpecified */
198 if(nsattr) {
199 nsIDOMAttr_Release(nsattr);
200 *p = VARIANT_TRUE;
201 }else {
202 *p = VARIANT_FALSE;
203 }
204 return S_OK;
205}
206
207static const IHTMLDOMAttributeVtbl HTMLDOMAttributeVtbl = {
208 HTMLDOMAttribute_QueryInterface,
209 HTMLDOMAttribute_AddRef,
210 HTMLDOMAttribute_Release,
211 HTMLDOMAttribute_GetTypeInfoCount,
212 HTMLDOMAttribute_GetTypeInfo,
213 HTMLDOMAttribute_GetIDsOfNames,
214 HTMLDOMAttribute_Invoke,
215 HTMLDOMAttribute_get_nodeName,
216 HTMLDOMAttribute_put_nodeValue,
217 HTMLDOMAttribute_get_nodeValue,
218 HTMLDOMAttribute_get_specified
219};
220
221static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute2(IHTMLDOMAttribute2 *iface)
222{
223 return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute2_iface);
224}
225
226static HRESULT WINAPI HTMLDOMAttribute2_QueryInterface(IHTMLDOMAttribute2 *iface, REFIID riid, void **ppv)
227{
228 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
229 return IHTMLDOMAttribute_QueryInterface(&This->IHTMLDOMAttribute_iface, riid, ppv);
230}
231
232static ULONG WINAPI HTMLDOMAttribute2_AddRef(IHTMLDOMAttribute2 *iface)
233{
234 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
235 return IHTMLDOMAttribute_AddRef(&This->IHTMLDOMAttribute_iface);
236}
237
238static ULONG WINAPI HTMLDOMAttribute2_Release(IHTMLDOMAttribute2 *iface)
239{
240 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
241 return IHTMLDOMAttribute_Release(&This->IHTMLDOMAttribute_iface);
242}
243
244static HRESULT WINAPI HTMLDOMAttribute2_GetTypeInfoCount(IHTMLDOMAttribute2 *iface, UINT *pctinfo)
245{
246 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
247 return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
248}
249
250static HRESULT WINAPI HTMLDOMAttribute2_GetTypeInfo(IHTMLDOMAttribute2 *iface, UINT iTInfo,
251 LCID lcid, ITypeInfo **ppTInfo)
252{
253 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
254 return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
255}
256
257static HRESULT WINAPI HTMLDOMAttribute2_GetIDsOfNames(IHTMLDOMAttribute2 *iface, REFIID riid,
258 LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
259{
260 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
261 return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
262 lcid, rgDispId);
263}
264
265static HRESULT WINAPI HTMLDOMAttribute2_Invoke(IHTMLDOMAttribute2 *iface, DISPID dispIdMember,
266 REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
267 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
268{
269 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
270 return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
271 wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
272}
273
274static HRESULT WINAPI HTMLDOMAttribute2_get_name(IHTMLDOMAttribute2 *iface, BSTR *p)
275{
276 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
277 FIXME("(%p)->(%p)\n", This, p);
278 return E_NOTIMPL;
279}
280
281static HRESULT WINAPI HTMLDOMAttribute2_put_value(IHTMLDOMAttribute2 *iface, BSTR v)
282{
283 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
284 FIXME("(%p)->(%s)\n", This, debugstr_w(v));
285 return E_NOTIMPL;
286}
287
288static HRESULT WINAPI HTMLDOMAttribute2_get_value(IHTMLDOMAttribute2 *iface, BSTR *p)
289{
290 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
291 VARIANT val;
292 HRESULT hres;
293
294 TRACE("(%p)->(%p)\n", This, p);
295
296 if(!This->elem) {
297 FIXME("NULL This->elem\n");
298 return E_UNEXPECTED;
299 }
300
301 hres = get_elem_attr_value_by_dispid(This->elem, This->dispid, ATTRFLAG_ASSTRING, &val);
302 if(FAILED(hres))
303 return hres;
304
305 assert(V_VT(&val) == VT_BSTR);
306 *p = V_BSTR(&val);
307 if(!*p && !(*p = SysAllocStringLen(NULL, 0)))
308 return E_OUTOFMEMORY;
309 return S_OK;
310}
311
312static HRESULT WINAPI HTMLDOMAttribute2_get_expando(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *p)
313{
314 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
315
316 TRACE("(%p)->(%p)\n", This, p);
317
318 *p = get_dispid_type(This->dispid) == DISPEXPROP_BUILTIN ? VARIANT_FALSE : VARIANT_TRUE;
319 return S_OK;
320}
321
322static HRESULT WINAPI HTMLDOMAttribute2_get_nodeType(IHTMLDOMAttribute2 *iface, LONG *p)
323{
324 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
325 FIXME("(%p)->(%p)\n", This, p);
326 return E_NOTIMPL;
327}
328
329static HRESULT WINAPI HTMLDOMAttribute2_get_parentNode(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
330{
331 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
332 FIXME("(%p)->(%p)\n", This, p);
333 return E_NOTIMPL;
334}
335
336static HRESULT WINAPI HTMLDOMAttribute2_get_childNodes(IHTMLDOMAttribute2 *iface, IDispatch **p)
337{
338 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
339 FIXME("(%p)->(%p)\n", This, p);
340 return E_NOTIMPL;
341}
342
343static HRESULT WINAPI HTMLDOMAttribute2_get_firstChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
344{
345 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
346 FIXME("(%p)->(%p)\n", This, p);
347 return E_NOTIMPL;
348}
349
350static HRESULT WINAPI HTMLDOMAttribute2_get_lastChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
351{
352 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
353 FIXME("(%p)->(%p)\n", This, p);
354 return E_NOTIMPL;
355}
356
357static HRESULT WINAPI HTMLDOMAttribute2_get_previousSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
358{
359 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
360 FIXME("(%p)->(%p)\n", This, p);
361 return E_NOTIMPL;
362}
363
364static HRESULT WINAPI HTMLDOMAttribute2_get_nextSibling(IHTMLDOMAttribute2 *iface, IHTMLDOMNode **p)
365{
366 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
367 FIXME("(%p)->(%p)\n", This, p);
368 return E_NOTIMPL;
369}
370
371static HRESULT WINAPI HTMLDOMAttribute2_get_attributes(IHTMLDOMAttribute2 *iface, IDispatch **p)
372{
373 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
374 FIXME("(%p)->(%p)\n", This, p);
375 return E_NOTIMPL;
376}
377
378static HRESULT WINAPI HTMLDOMAttribute2_get_ownerDocument(IHTMLDOMAttribute2 *iface, IDispatch **p)
379{
380 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
381 FIXME("(%p)->(%p)\n", This, p);
382 return E_NOTIMPL;
383}
384
385static HRESULT WINAPI HTMLDOMAttribute2_insertBefore(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
386 VARIANT refChild, IHTMLDOMNode **node)
387{
388 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
389 FIXME("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), node);
390 return E_NOTIMPL;
391}
392
393static HRESULT WINAPI HTMLDOMAttribute2_replaceChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
394 IHTMLDOMNode *oldChild, IHTMLDOMNode **node)
395{
396 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
397 FIXME("(%p)->(%p %p %p)\n", This, newChild, oldChild, node);
398 return E_NOTIMPL;
399}
400
401static HRESULT WINAPI HTMLDOMAttribute2_removeChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *oldChild,
402 IHTMLDOMNode **node)
403{
404 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
405 FIXME("(%p)->(%p %p)\n", This, oldChild, node);
406 return E_NOTIMPL;
407}
408
409static HRESULT WINAPI HTMLDOMAttribute2_appendChild(IHTMLDOMAttribute2 *iface, IHTMLDOMNode *newChild,
410 IHTMLDOMNode **node)
411{
412 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
413 FIXME("(%p)->(%p %p)\n", This, newChild, node);
414 return E_NOTIMPL;
415}
416
417static HRESULT WINAPI HTMLDOMAttribute2_hasChildNodes(IHTMLDOMAttribute2 *iface, VARIANT_BOOL *fChildren)
418{
419 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
420 FIXME("(%p)->(%p)\n", This, fChildren);
421 return E_NOTIMPL;
422}
423
424static HRESULT WINAPI HTMLDOMAttribute2_cloneNode(IHTMLDOMAttribute2 *iface, VARIANT_BOOL fDeep,
425 IHTMLDOMAttribute **clonedNode)
426{
427 HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute2(iface);
428 FIXME("(%p)->(%x %p)\n", This, fDeep, clonedNode);
429 return E_NOTIMPL;
430}
431
432static const IHTMLDOMAttribute2Vtbl HTMLDOMAttribute2Vtbl = {
433 HTMLDOMAttribute2_QueryInterface,
434 HTMLDOMAttribute2_AddRef,
435 HTMLDOMAttribute2_Release,
436 HTMLDOMAttribute2_GetTypeInfoCount,
437 HTMLDOMAttribute2_GetTypeInfo,
438 HTMLDOMAttribute2_GetIDsOfNames,
439 HTMLDOMAttribute2_Invoke,
440 HTMLDOMAttribute2_get_name,
441 HTMLDOMAttribute2_put_value,
442 HTMLDOMAttribute2_get_value,
443 HTMLDOMAttribute2_get_expando,
444 HTMLDOMAttribute2_get_nodeType,
445 HTMLDOMAttribute2_get_parentNode,
446 HTMLDOMAttribute2_get_childNodes,
447 HTMLDOMAttribute2_get_firstChild,
448 HTMLDOMAttribute2_get_lastChild,
449 HTMLDOMAttribute2_get_previousSibling,
450 HTMLDOMAttribute2_get_nextSibling,
451 HTMLDOMAttribute2_get_attributes,
452 HTMLDOMAttribute2_get_ownerDocument,
453 HTMLDOMAttribute2_insertBefore,
454 HTMLDOMAttribute2_replaceChild,
455 HTMLDOMAttribute2_removeChild,
456 HTMLDOMAttribute2_appendChild,
457 HTMLDOMAttribute2_hasChildNodes,
458 HTMLDOMAttribute2_cloneNode
459};
460
461static const tid_t HTMLDOMAttribute_iface_tids[] = {
462 IHTMLDOMAttribute_tid,
463 IHTMLDOMAttribute2_tid,
464 0
465};
466static dispex_static_data_t HTMLDOMAttribute_dispex = {
467 NULL,
468 DispHTMLDOMAttribute_tid,
469 0,
470 HTMLDOMAttribute_iface_tids
471};
472
473HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, HTMLDOMAttribute **attr)
474{
475 HTMLAttributeCollection *col;
476 HTMLDOMAttribute *ret;
477 HRESULT hres;
478
479 ret = heap_alloc_zero(sizeof(*ret));
480 if(!ret)
481 return E_OUTOFMEMORY;
482
483 ret->IHTMLDOMAttribute_iface.lpVtbl = &HTMLDOMAttributeVtbl;
484 ret->IHTMLDOMAttribute2_iface.lpVtbl = &HTMLDOMAttribute2Vtbl;
485 ret->ref = 1;
486 ret->dispid = dispid;
487 ret->elem = elem;
488
489 init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface,
490 &HTMLDOMAttribute_dispex);
491
492 /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */
493 if(elem) {
494 hres = HTMLElement_get_attr_col(&elem->node, &col);
495 if(FAILED(hres)) {
496 IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
497 return hres;
498 }
499 IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface);
500
501 list_add_tail(&elem->attrs->attrs, &ret->entry);
502 }
503
504 /* For detached attributes we may still do most operations if we have its name available. */
505 if(name) {
506 ret->name = heap_strdupW(name);
507 if(!ret->name) {
508 IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
509 return E_OUTOFMEMORY;
510 }
511 }
512
513 *attr = ret;
514 return S_OK;
515}