Release 1.5.29.
[wine] / dlls / 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
20 #include <stdarg.h>
21 #include <assert.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "ole2.h"
29
30 #include "mshtml_private.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
35
36 static inline HTMLDOMAttribute *impl_from_IHTMLDOMAttribute(IHTMLDOMAttribute *iface)
37 {
38     return CONTAINING_RECORD(iface, HTMLDOMAttribute, IHTMLDOMAttribute_iface);
39 }
40
41 static HRESULT WINAPI HTMLDOMAttribute_QueryInterface(IHTMLDOMAttribute *iface,
42                                                  REFIID riid, void **ppv)
43 {
44     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
45
46     if(IsEqualGUID(&IID_IUnknown, riid)) {
47         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
48         *ppv = &This->IHTMLDOMAttribute_iface;
49     }else if(IsEqualGUID(&IID_IHTMLDOMAttribute, riid)) {
50         TRACE("(%p)->(IID_IHTMLDOMAttribute %p)\n", This, ppv);
51         *ppv = &This->IHTMLDOMAttribute_iface;
52     }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
53         return *ppv ? S_OK : E_NOINTERFACE;
54     }else {
55         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
56         *ppv =  NULL;
57         return E_NOINTERFACE;
58     }
59
60     IUnknown_AddRef((IUnknown*)*ppv);
61     return S_OK;
62 }
63
64 static ULONG WINAPI HTMLDOMAttribute_AddRef(IHTMLDOMAttribute *iface)
65 {
66     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
67     LONG ref = InterlockedIncrement(&This->ref);
68
69     TRACE("(%p) ref=%d\n", This, ref);
70
71     return ref;
72 }
73
74 static ULONG WINAPI HTMLDOMAttribute_Release(IHTMLDOMAttribute *iface)
75 {
76     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
77     LONG ref = InterlockedDecrement(&This->ref);
78
79     TRACE("(%p) ref=%d\n", This, ref);
80
81     if(!ref) {
82         assert(!This->elem);
83         release_dispex(&This->dispex);
84         heap_free(This->name);
85         heap_free(This);
86     }
87
88     return ref;
89 }
90
91 static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfoCount(IHTMLDOMAttribute *iface, UINT *pctinfo)
92 {
93     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
94     return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
95 }
96
97 static HRESULT WINAPI HTMLDOMAttribute_GetTypeInfo(IHTMLDOMAttribute *iface, UINT iTInfo,
98                                               LCID lcid, ITypeInfo **ppTInfo)
99 {
100     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
101     return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
102 }
103
104 static HRESULT WINAPI HTMLDOMAttribute_GetIDsOfNames(IHTMLDOMAttribute *iface, REFIID riid,
105                                                 LPOLESTR *rgszNames, UINT cNames,
106                                                 LCID lcid, DISPID *rgDispId)
107 {
108     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
109     return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames, cNames,
110             lcid, rgDispId);
111 }
112
113 static HRESULT WINAPI HTMLDOMAttribute_Invoke(IHTMLDOMAttribute *iface, DISPID dispIdMember,
114                             REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
115                             VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
116 {
117     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
118     return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid, lcid,
119             wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
120 }
121
122 static HRESULT WINAPI HTMLDOMAttribute_get_nodeName(IHTMLDOMAttribute *iface, BSTR *p)
123 {
124     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
125
126     TRACE("(%p)->(%p)\n", This, p);
127
128     if(!This->elem) {
129         if(!This->name) {
130             FIXME("No name available\n");
131             return E_FAIL;
132         }
133
134         *p = SysAllocString(This->name);
135         return *p ? S_OK : E_OUTOFMEMORY;
136     }
137
138     return IDispatchEx_GetMemberName(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, p);
139 }
140
141 static HRESULT WINAPI HTMLDOMAttribute_put_nodeName(IHTMLDOMAttribute *iface, VARIANT v)
142 {
143     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
144     FIXME("(%p)->(%s)\n", This, debugstr_variant(&v));
145     return E_NOTIMPL;
146 }
147
148 static HRESULT WINAPI HTMLDOMAttribute_get_nodeValue(IHTMLDOMAttribute *iface, VARIANT *p)
149 {
150     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
151     DISPPARAMS dp = {NULL, NULL, 0, 0};
152     EXCEPINFO ei;
153
154     TRACE("(%p)->(%p)\n", This, p);
155
156     if(!This->elem) {
157         FIXME("NULL This->elem\n");
158         return E_UNEXPECTED;
159     }
160
161     memset(&ei, 0, sizeof(ei));
162     return IDispatchEx_InvokeEx(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, LOCALE_SYSTEM_DEFAULT,
163             DISPATCH_PROPERTYGET, &dp, p, &ei, NULL);
164 }
165
166 static HRESULT WINAPI HTMLDOMAttribute_get_specified(IHTMLDOMAttribute *iface, VARIANT_BOOL *p)
167 {
168     HTMLDOMAttribute *This = impl_from_IHTMLDOMAttribute(iface);
169     nsIDOMAttr *nsattr;
170     nsAString nsname;
171     BSTR name;
172     nsresult nsres;
173     HRESULT hres;
174
175     TRACE("(%p)->(%p)\n", This, p);
176
177     if(!This->elem || !This->elem->nselem) {
178         FIXME("NULL This->elem\n");
179         return E_UNEXPECTED;
180     }
181
182     if(get_dispid_type(This->dispid) != DISPEXPROP_BUILTIN) {
183         *p = VARIANT_TRUE;
184         return S_OK;
185     }
186
187     hres = IDispatchEx_GetMemberName(&This->elem->node.dispex.IDispatchEx_iface, This->dispid, &name);
188     if(FAILED(hres))
189         return hres;
190
191     /* FIXME: This is not exactly right, we have some attributes that don't map directly to Gecko attributes. */
192     nsAString_InitDepend(&nsname, name);
193     nsres = nsIDOMHTMLElement_GetAttributeNode(This->elem->nselem, &nsname, &nsattr);
194     nsAString_Finish(&nsname);
195     SysFreeString(name);
196     if(NS_FAILED(nsres))
197         return E_FAIL;
198
199     /* If the Gecko attribute node can be found, we know that the attribute is specified.
200        There is no point in calling GetSpecified */
201     if(nsattr) {
202         nsIDOMAttr_Release(nsattr);
203         *p = VARIANT_TRUE;
204     }else {
205         *p = VARIANT_FALSE;
206     }
207     return S_OK;
208 }
209
210 static const IHTMLDOMAttributeVtbl HTMLDOMAttributeVtbl = {
211     HTMLDOMAttribute_QueryInterface,
212     HTMLDOMAttribute_AddRef,
213     HTMLDOMAttribute_Release,
214     HTMLDOMAttribute_GetTypeInfoCount,
215     HTMLDOMAttribute_GetTypeInfo,
216     HTMLDOMAttribute_GetIDsOfNames,
217     HTMLDOMAttribute_Invoke,
218     HTMLDOMAttribute_get_nodeName,
219     HTMLDOMAttribute_put_nodeName,
220     HTMLDOMAttribute_get_nodeValue,
221     HTMLDOMAttribute_get_specified
222 };
223
224 static const tid_t HTMLDOMAttribute_iface_tids[] = {
225     IHTMLDOMAttribute_tid,
226     0
227 };
228 static dispex_static_data_t HTMLDOMAttribute_dispex = {
229     NULL,
230     DispHTMLDOMAttribute_tid,
231     0,
232     HTMLDOMAttribute_iface_tids
233 };
234
235 HRESULT HTMLDOMAttribute_Create(const WCHAR *name, HTMLElement *elem, DISPID dispid, HTMLDOMAttribute **attr)
236 {
237     HTMLAttributeCollection *col;
238     HTMLDOMAttribute *ret;
239     HRESULT hres;
240
241     ret = heap_alloc_zero(sizeof(*ret));
242     if(!ret)
243         return E_OUTOFMEMORY;
244
245     ret->IHTMLDOMAttribute_iface.lpVtbl = &HTMLDOMAttributeVtbl;
246     ret->ref = 1;
247     ret->dispid = dispid;
248     ret->elem = elem;
249
250     init_dispex(&ret->dispex, (IUnknown*)&ret->IHTMLDOMAttribute_iface,
251             &HTMLDOMAttribute_dispex);
252
253     /* For attributes attached to an element, (elem,dispid) pair should be valid used for its operation. */
254     if(elem) {
255         hres = HTMLElement_get_attr_col(&elem->node, &col);
256         if(FAILED(hres)) {
257             IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
258             return hres;
259         }
260         IHTMLAttributeCollection_Release(&col->IHTMLAttributeCollection_iface);
261
262         list_add_tail(&elem->attrs->attrs, &ret->entry);
263     }
264
265     /* For detached attributes we may still do most operations if we have its name available. */
266     if(name) {
267         ret->name = heap_strdupW(name);
268         if(!ret->name) {
269             IHTMLDOMAttribute_Release(&ret->IHTMLDOMAttribute_iface);
270             return E_OUTOFMEMORY;
271         }
272     }
273
274     *attr = ret;
275     return S_OK;
276 }