2 * Copyright 2007 Jacek Caban for CodeWeavers
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.
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.
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
22 #include <wine/test.h>
32 static const char doc_blank
[] = "<html></html>";
33 static const char doc_str1
[] = "<html><body>test</body></html>";
34 static const char doc_str2
[] =
35 "<html><body>test a<font size=\"2\">bc 123<br />it's </font>text<br /></body></html>";
37 static const WCHAR noneW
[] = {'N','o','n','e',0};
39 static WCHAR characterW
[] = {'c','h','a','r','a','c','t','e','r',0};
40 static WCHAR wordW
[] = {'w','o','r','d',0};
42 static const char *dbgstr_w(LPCWSTR str
)
47 WideCharToMultiByte(CP_ACP
, 0, str
, -1, buf
, sizeof(buf
), NULL
, NULL
);
51 static int strcmp_wa(LPCWSTR strw
, const char *stra
)
54 MultiByteToWideChar(CP_ACP
, 0, stra
, -1, buf
, sizeof(buf
)/sizeof(WCHAR
));
55 return lstrcmpW(strw
, buf
);
58 static IHTMLDocument2
*create_document(void)
63 hres
= CoCreateInstance(&CLSID_HTMLDocument
, NULL
, CLSCTX_INPROC_SERVER
|CLSCTX_INPROC_HANDLER
,
64 &IID_IHTMLDocument2
, (void**)&doc
);
65 ok(hres
== S_OK
, "CoCreateInstance failed: %08x\n", hres
);
70 #define test_node_name(u,n) _test_node_name(__LINE__,u,n)
71 static void _test_node_name(unsigned line
, IUnknown
*unk
, const char *exname
)
77 hres
= IUnknown_QueryInterface(unk
, &IID_IHTMLDOMNode
, (void**)&node
);
78 ok_(__FILE__
, line
) (hres
== S_OK
, "QueryInterface(IID_IHTMLNode) failed: %08x\n", hres
);
80 hres
= IHTMLDOMNode_get_nodeName(node
, &name
);
81 IHTMLDOMNode_Release(node
);
82 ok_(__FILE__
, line
) (hres
== S_OK
, "get_nodeName failed: %08x\n", hres
);
83 ok_(__FILE__
, line
) (!strcmp_wa(name
, exname
), "got name: %s, expected HTML\n", dbgstr_w(name
));
88 static void test_doc_elem(IHTMLDocument2
*doc
)
94 hres
= IHTMLDocument2_QueryInterface(doc
, &IID_IHTMLDocument3
, (void**)&doc3
);
95 ok(hres
== S_OK
, "QueryInterface(IID_IHTMLDocument3) failed: %08x\n", hres
);
97 hres
= IHTMLDocument3_get_documentElement(doc3
, &elem
);
98 IHTMLDocument3_Release(doc3
);
99 ok(hres
== S_OK
, "get_documentElement failed: %08x\n", hres
);
101 test_node_name((IUnknown
*)elem
, "HTML");
103 IHTMLElement_Release(elem
);
106 #define test_range_text(r,t) _test_range_text(__LINE__,r,t)
107 static void _test_range_text(unsigned line
, IHTMLTxtRange
*range
, const char *extext
)
112 hres
= IHTMLTxtRange_get_text(range
, &text
);
113 ok_(__FILE__
, line
) (hres
== S_OK
, "get_text failed: %08x\n", hres
);
116 ok_(__FILE__
, line
) (text
!= NULL
, "text == NULL\n");
117 ok_(__FILE__
, line
) (!strcmp_wa(text
, extext
), "text=\"%s\", expected \"%s\"\n", dbgstr_w(text
), extext
);
119 ok_(__FILE__
, line
) (text
== NULL
, "text=\"%s\", expected NULL\n", dbgstr_w(text
));
126 #define test_range_collapse(r,b) _test_range_collapse(__LINE__,r,b)
127 static void _test_range_collapse(unsigned line
, IHTMLTxtRange
*range
, BOOL b
)
131 hres
= IHTMLTxtRange_collapse(range
, b
);
132 ok_(__FILE__
, line
) (hres
== S_OK
, "collapse failed: %08x\n", hres
);
133 _test_range_text(line
, range
, NULL
);
136 #define test_range_expand(r,u,b,t) _test_range_expand(__LINE__,r,u,b,t)
137 static void _test_range_expand(unsigned line
, IHTMLTxtRange
*range
, LPWSTR unit
,
138 VARIANT_BOOL exb
, const char *extext
)
140 VARIANT_BOOL b
= 0xe0e0;
143 hres
= IHTMLTxtRange_expand(range
, unit
, &b
);
144 ok_(__FILE__
,line
) (hres
== S_OK
, "expand failed: %08x\n", hres
);
145 ok_(__FILE__
,line
) (b
== exb
, "b=%x, expected %x\n", b
, exb
);
146 _test_range_text(line
, range
, extext
);
149 #define test_range_move(r,u,c,e) _test_range_move(__LINE__,r,u,c,e)
150 static void _test_range_move(unsigned line
, IHTMLTxtRange
*range
, LPWSTR unit
, long cnt
, long excnt
)
155 hres
= IHTMLTxtRange_move(range
, unit
, cnt
, &c
);
156 ok_(__FILE__
,line
) (hres
== S_OK
, "move failed: %08x\n", hres
);
157 ok_(__FILE__
,line
) (c
== excnt
, "count=%ld, expected %ld\n", c
, excnt
);
158 _test_range_text(line
, range
, NULL
);
161 #define test_range_moveend(r,u,c,e) _test_range_moveend(__LINE__,r,u,c,e)
162 static void _test_range_moveend(unsigned line
, IHTMLTxtRange
*range
, LPWSTR unit
, long cnt
, long excnt
)
167 hres
= IHTMLTxtRange_moveEnd(range
, unit
, cnt
, &c
);
168 ok_(__FILE__
,line
) (hres
== S_OK
, "move failed: %08x\n", hres
);
169 ok_(__FILE__
,line
) (c
== excnt
, "count=%ld, expected %ld\n", c
, excnt
);
172 #define test_range_put_text(r,t) _test_range_put_text(__LINE__,r,t)
173 static void _test_range_put_text(unsigned line
, IHTMLTxtRange
*range
, LPCWSTR text
)
177 hres
= IHTMLTxtRange_put_text(range
, (BSTR
)text
);
178 ok_(__FILE__
,line
) (hres
== S_OK
, "put_text failed: %08x\n", hres
);
179 _test_range_text(line
, range
, NULL
);
182 #define test_range_inrange(r1,r2,b) _test_range_inrange(__LINE__,r1,r2,b)
183 static void _test_range_inrange(unsigned line
, IHTMLTxtRange
*range1
, IHTMLTxtRange
*range2
, VARIANT_BOOL exb
)
189 hres
= IHTMLTxtRange_inRange(range1
, range2
, &b
);
190 ok_(__FILE__
,line
) (hres
== S_OK
, "(1->2) isEqual failed: %08x\n", hres
);
191 ok_(__FILE__
,line
) (b
== exb
, "(1->2) b=%x, expected %x\n", b
, exb
);
194 #define test_range_isequal(r1,r2,b) _test_range_isequal(__LINE__,r1,r2,b)
195 static void _test_range_isequal(unsigned line
, IHTMLTxtRange
*range1
, IHTMLTxtRange
*range2
, VARIANT_BOOL exb
)
201 hres
= IHTMLTxtRange_isEqual(range1
, range2
, &b
);
202 ok_(__FILE__
,line
) (hres
== S_OK
, "(1->2) isEqual failed: %08x\n", hres
);
203 ok_(__FILE__
,line
) (b
== exb
, "(1->2) b=%x, expected %x\n", b
, exb
);
206 hres
= IHTMLTxtRange_isEqual(range2
, range1
, &b
);
207 ok_(__FILE__
,line
) (hres
== S_OK
, "(2->1) isEqual failed: %08x\n", hres
);
208 ok_(__FILE__
,line
) (b
== exb
, "(2->1) b=%x, expected %x\n", b
, exb
);
211 test_range_inrange(range1
, range2
, VARIANT_TRUE
);
212 test_range_inrange(range2
, range1
, VARIANT_TRUE
);
216 static void test_txtrange(IHTMLDocument2
*doc
)
219 IHTMLBodyElement
*body
;
220 IHTMLTxtRange
*body_range
, *range
, *range2
;
223 hres
= IHTMLDocument2_get_body(doc
, &elem
);
224 ok(hres
== S_OK
, "get_body failed: %08x\n", hres
);
226 hres
= IHTMLElement_QueryInterface(elem
, &IID_IHTMLBodyElement
, (void**)&body
);
227 IHTMLElement_Release(elem
);
229 hres
= IHTMLBodyElement_createTextRange(body
, &body_range
);
230 IHTMLBodyElement_Release(body
);
231 ok(hres
== S_OK
, "createTextRange failed: %08x\n", hres
);
233 test_range_text(body_range
, "test abc 123\r\nit's text");
235 hres
= IHTMLTxtRange_duplicate(body_range
, &range
);
236 ok(hres
== S_OK
, "duplicate failed: %08x\n", hres
);
238 hres
= IHTMLTxtRange_duplicate(body_range
, &range2
);
239 ok(hres
== S_OK
, "duplicate failed: %08x\n", hres
);
240 test_range_isequal(range
, range2
, VARIANT_TRUE
);
242 test_range_text(range
, "test abc 123\r\nit's text");
243 test_range_text(body_range
, "test abc 123\r\nit's text");
245 test_range_collapse(range
, TRUE
);
246 test_range_isequal(range
, range2
, VARIANT_FALSE
);
247 test_range_inrange(range
, range2
, VARIANT_FALSE
);
248 test_range_inrange(range2
, range
, VARIANT_TRUE
);
249 IHTMLTxtRange_Release(range2
);
251 test_range_expand(range
, wordW
, VARIANT_TRUE
, "test ");
252 test_range_expand(range
, wordW
, VARIANT_FALSE
, "test ");
253 test_range_move(range
, characterW
, 2, 2);
254 test_range_expand(range
, wordW
, VARIANT_TRUE
, "test ");
256 test_range_collapse(range
, FALSE
);
257 test_range_expand(range
, wordW
, VARIANT_TRUE
, "abc ");
259 test_range_collapse(range
, FALSE
);
260 test_range_expand(range
, wordW
, VARIANT_TRUE
, "123");
261 test_range_expand(range
, wordW
, VARIANT_FALSE
, "123");
262 test_range_move(range
, characterW
, 2, 2);
263 test_range_expand(range
, wordW
, VARIANT_TRUE
, "123");
265 IHTMLTxtRange_Release(range
);
267 hres
= IHTMLTxtRange_duplicate(body_range
, &range
);
268 ok(hres
== S_OK
, "duplicate failed: %08x\n", hres
);
270 test_range_text(range
, "test abc 123\r\nit's text");
271 test_range_move(range
, characterW
, 3, 3);
272 test_range_moveend(range
, characterW
, 1, 1);
273 test_range_text(range
, "t");
274 test_range_moveend(range
, characterW
, 3, 3);
275 test_range_text(range
, "t ab");
276 test_range_moveend(range
, characterW
, -2, -2);
277 test_range_text(range
, "t ");
278 test_range_move(range
, characterW
, 6, 6);
279 test_range_moveend(range
, characterW
, 3, 3);
280 test_range_text(range
, "123");
281 test_range_moveend(range
, characterW
, 2, 2);
282 test_range_text(range
, "123\r\ni");
284 IHTMLTxtRange_Release(range
);
286 hres
= IHTMLTxtRange_duplicate(body_range
, &range
);
287 ok(hres
== S_OK
, "duplicate failed: %08x\n", hres
);
289 test_range_move(range
, wordW
, 1, 1);
290 test_range_moveend(range
, characterW
, 2, 2);
291 test_range_text(range
, "ab");
293 test_range_move(range
, characterW
, -2, -2);
294 test_range_moveend(range
, characterW
, 2, 2);
295 test_range_text(range
, "t ");
297 test_range_move(range
, wordW
, 3, 3);
298 test_range_move(range
, wordW
, -2, -2);
299 test_range_moveend(range
, characterW
, 2, 2);
300 test_range_text(range
, "ab");
302 test_range_move(range
, characterW
, -6, -5);
303 test_range_moveend(range
, characterW
, -1, 0);
304 test_range_moveend(range
, characterW
, -6, 0);
305 test_range_move(range
, characterW
, 2, 2);
306 test_range_moveend(range
, characterW
, 2, 2);
307 test_range_text(range
, "st");
308 test_range_moveend(range
, characterW
, -6, -4);
309 test_range_moveend(range
, characterW
, 2, 2);
311 IHTMLTxtRange_Release(range
);
313 hres
= IHTMLTxtRange_duplicate(body_range
, &range
);
314 ok(hres
== S_OK
, "duplicate failed: %08x\n", hres
);
316 test_range_move(range
, wordW
, 2, 2);
317 test_range_moveend(range
, characterW
, 2, 2);
318 test_range_text(range
, "12");
320 test_range_move(range
, characterW
, 15, 14);
321 test_range_move(range
, characterW
, -2, -2);
322 test_range_moveend(range
, characterW
, 3, 2);
323 test_range_text(range
, "t");
324 test_range_moveend(range
, characterW
, -1, -1);
325 test_range_text(range
, "t");
326 test_range_expand(range
, wordW
, VARIANT_TRUE
, "text");
327 test_range_move(range
, characterW
, -2, -2);
328 test_range_moveend(range
, characterW
, 2, 2);
329 test_range_text(range
, "s ");
330 test_range_move(range
, characterW
, 100, 7);
331 test_range_move(range
, wordW
, 1, 0);
332 test_range_move(range
, characterW
, -2, -2);
333 test_range_moveend(range
, characterW
, 3, 2);
334 test_range_text(range
, "t");
336 IHTMLTxtRange_Release(range
);
338 hres
= IHTMLTxtRange_duplicate(body_range
, &range
);
339 ok(hres
== S_OK
, "duplicate failed: %08x\n", hres
);
341 test_range_collapse(range
, TRUE
);
342 test_range_expand(range
, wordW
, VARIANT_TRUE
, "test ");
343 test_range_put_text(range
, wordW
);
344 test_range_text(body_range
, "wordabc 123\r\nit's text");
346 IHTMLTxtRange_Release(range
);
347 IHTMLTxtRange_Release(body_range
);
350 static void test_compatmode(IHTMLDocument2
*doc
)
352 IHTMLDocument5
*doc5
;
356 hres
= IHTMLDocument2_QueryInterface(doc
, &IID_IHTMLDocument5
, (void**)&doc5
);
357 ok(hres
== S_OK
, "Could not get IHTMLDocument5 interface: %08x\n", hres
);
361 hres
= IHTMLDocument5_get_compatMode(doc5
, &mode
);
362 IHTMLDocument5_Release(doc5
);
363 ok(hres
== S_OK
, "get_compatMode failed: %08x\n", hres
);
364 ok(!strcmp_wa(mode
, "BackCompat"), "compatMode=%s\n", dbgstr_w(mode
));
368 static void test_default_style(IHTMLStyle
*style
)
375 str
= (void*)0xdeadbeef;
376 hres
= IHTMLStyle_get_fontFamily(style
, &str
);
377 ok(hres
== S_OK
, "get_fontFamily failed: %08x\n", hres
);
378 ok(!str
, "fontFamily = %s\n", dbgstr_w(str
));
380 str
= (void*)0xdeadbeef;
381 hres
= IHTMLStyle_get_fontWeight(style
, &str
);
382 ok(hres
== S_OK
, "get_fontWeight failed: %08x\n", hres
);
383 ok(!str
, "fontWeight = %s\n", dbgstr_w(str
));
386 hres
= IHTMLStyle_get_fontSize(style
, &v
);
387 ok(hres
== S_OK
, "get_fontSize failed: %08x\n", hres
);
388 ok(V_VT(&v
) == VT_BSTR
, "V_VT(fontSize) = %d\n", V_VT(&v
));
389 ok(!V_BSTR(&v
), "V_BSTR(fontSize) = %s\n", dbgstr_w(V_BSTR(&v
)));
392 hres
= IHTMLStyle_get_color(style
, &v
);
393 ok(hres
== S_OK
, "get_color failed: %08x\n", hres
);
394 ok(V_VT(&v
) == VT_BSTR
, "V_VT(color) = %d\n", V_VT(&v
));
395 ok(!V_BSTR(&v
), "V_BSTR(color) = %s\n", dbgstr_w(V_BSTR(&v
)));
398 hres
= IHTMLStyle_get_textDecorationUnderline(style
, &b
);
399 ok(hres
== S_OK
, "get_textDecorationUnderline failed: %08x\n", hres
);
400 ok(b
== VARIANT_FALSE
, "textDecorationUnderline = %x\n", b
);
403 hres
= IHTMLStyle_get_textDecorationLineThrough(style
, &b
);
404 ok(hres
== S_OK
, "get_textDecorationLineThrough failed: %08x\n", hres
);
405 ok(b
== VARIANT_FALSE
, "textDecorationLineThrough = %x\n", b
);
408 static void test_default_selection(IHTMLDocument2
*doc
)
410 IHTMLSelectionObject
*selection
;
411 IHTMLTxtRange
*range
;
416 hres
= IHTMLDocument2_get_selection(doc
, &selection
);
417 ok(hres
== S_OK
, "get_selection failed: %08x\n", hres
);
419 hres
= IHTMLSelectionObject_get_type(selection
, &str
);
420 ok(hres
== S_OK
, "get_type failed: %08x\n", hres
);
421 ok(!lstrcmpW(str
, noneW
), "type = %s\n", dbgstr_w(str
));
424 hres
= IHTMLSelectionObject_createRange(selection
, &disp
);
425 IHTMLSelectionObject_Release(selection
);
426 ok(hres
== S_OK
, "createRange failed: %08x\n", hres
);
428 hres
= IDispatch_QueryInterface(disp
, &IID_IHTMLTxtRange
, (void**)&range
);
429 IDispatch_Release(disp
);
430 ok(hres
== S_OK
, "Could not get IHTMLTxtRange interface: %08x\n", hres
);
432 test_range_text(range
, NULL
);
433 IHTMLTxtRange_Release(range
);
436 static void test_defaults(IHTMLDocument2
*doc
)
438 IHTMLStyleSheetsCollection
*stylesheetcol
;
444 hres
= IHTMLDocument2_get_body(doc
, &elem
);
445 ok(hres
== S_OK
, "get_body failed: %08x\n", hres
);
447 hres
= IHTMLElement_get_style(elem
, &style
);
448 IHTMLElement_Release(elem
);
449 ok(hres
== S_OK
, "get_style failed: %08x\n", hres
);
451 test_default_style(style
);
452 test_compatmode(doc
);
454 IHTMLStyle_Release(style
);
456 hres
= IHTMLDocument2_get_styleSheets(doc
, &stylesheetcol
);
457 ok(hres
== S_OK
, "get_styleSheets failed: %08x\n", hres
);
460 hres
= IHTMLStyleSheetsCollection_get_length(stylesheetcol
, &l
);
461 ok(hres
== S_OK
, "get_length failed: %08x\n", hres
);
462 ok(l
== 0, "length = %ld\n", l
);
464 IHTMLStyleSheetsCollection_Release(stylesheetcol
);
466 test_default_selection(doc
);
469 static IHTMLDocument2
*notif_doc
;
470 static BOOL doc_complete
;
472 static HRESULT WINAPI
PropertyNotifySink_QueryInterface(IPropertyNotifySink
*iface
,
473 REFIID riid
, void**ppv
)
475 if(IsEqualGUID(&IID_IPropertyNotifySink
, riid
)) {
480 ok(0, "unexpected call\n");
481 return E_NOINTERFACE
;
484 static ULONG WINAPI
PropertyNotifySink_AddRef(IPropertyNotifySink
*iface
)
489 static ULONG WINAPI
PropertyNotifySink_Release(IPropertyNotifySink
*iface
)
494 static HRESULT WINAPI
PropertyNotifySink_OnChanged(IPropertyNotifySink
*iface
, DISPID dispID
)
496 if(dispID
== DISPID_READYSTATE
){
500 static const WCHAR completeW
[] = {'c','o','m','p','l','e','t','e',0};
502 hres
= IHTMLDocument2_get_readyState(notif_doc
, &state
);
503 ok(hres
== S_OK
, "get_readyState failed: %08x\n", hres
);
505 if(!lstrcmpW(state
, completeW
))
508 SysFreeString(state
);
514 static HRESULT WINAPI
PropertyNotifySink_OnRequestEdit(IPropertyNotifySink
*iface
, DISPID dispID
)
516 ok(0, "unexpected call\n");
520 static IPropertyNotifySinkVtbl PropertyNotifySinkVtbl
= {
521 PropertyNotifySink_QueryInterface
,
522 PropertyNotifySink_AddRef
,
523 PropertyNotifySink_Release
,
524 PropertyNotifySink_OnChanged
,
525 PropertyNotifySink_OnRequestEdit
528 static IPropertyNotifySink PropertyNotifySink
= { &PropertyNotifySinkVtbl
};
530 static IHTMLDocument2
*create_doc_with_string(const char *str
)
532 IPersistStreamInit
*init
;
538 notif_doc
= doc
= create_document();
542 doc_complete
= FALSE
;
544 mem
= GlobalAlloc(0, len
);
545 memcpy(mem
, str
, len
);
546 CreateStreamOnHGlobal(mem
, TRUE
, &stream
);
548 IHTMLDocument2_QueryInterface(doc
, &IID_IPersistStreamInit
, (void**)&init
);
550 IPersistStreamInit_Load(init
, stream
);
551 IPersistStreamInit_Release(init
);
552 IStream_Release(stream
);
557 static void do_advise(IUnknown
*unk
, REFIID riid
, IUnknown
*unk_advise
)
559 IConnectionPointContainer
*container
;
560 IConnectionPoint
*cp
;
564 hres
= IUnknown_QueryInterface(unk
, &IID_IConnectionPointContainer
, (void**)&container
);
565 ok(hres
== S_OK
, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres
);
567 hres
= IConnectionPointContainer_FindConnectionPoint(container
, riid
, &cp
);
568 IConnectionPointContainer_Release(container
);
569 ok(hres
== S_OK
, "FindConnectionPoint failed: %08x\n", hres
);
571 hres
= IConnectionPoint_Advise(cp
, unk_advise
, &cookie
);
572 IConnectionPoint_Release(cp
);
573 ok(hres
== S_OK
, "Advise failed: %08x\n", hres
);
576 typedef void (*domtest_t
)(IHTMLDocument2
*);
578 static void run_domtest(const char *str
, domtest_t test
)
584 doc
= create_doc_with_string(str
);
585 do_advise((IUnknown
*)doc
, &IID_IPropertyNotifySink
, (IUnknown
*)&PropertyNotifySink
);
587 while(!doc_complete
&& GetMessage(&msg
, NULL
, 0, 0)) {
588 TranslateMessage(&msg
);
589 DispatchMessage(&msg
);
594 ref
= IHTMLDocument2_Release(doc
);
595 ok(!ref
, "ref = %d\n", ref
);
598 static void gecko_installer_workaround(BOOL disable
)
603 static BOOL has_url
= FALSE
;
604 static char url
[2048];
606 if(!disable
&& !has_url
)
609 res
= RegOpenKey(HKEY_CURRENT_USER
, "Software\\Wine\\MSHTML", &hkey
);
610 if(res
!= ERROR_SUCCESS
)
614 DWORD type
, size
= sizeof(url
);
616 res
= RegQueryValueEx(hkey
, "GeckoUrl", NULL
, &type
, (PVOID
)url
, &size
);
617 if(res
== ERROR_SUCCESS
&& type
== REG_SZ
)
620 RegDeleteValue(hkey
, "GeckoUrl");
622 RegSetValueEx(hkey
, "GeckoUrl", 0, REG_SZ
, (PVOID
)url
, lstrlenA(url
)+1);
630 gecko_installer_workaround(TRUE
);
633 run_domtest(doc_str1
, test_doc_elem
);
634 run_domtest(doc_str2
, test_txtrange
);
635 run_domtest(doc_blank
, test_defaults
);
638 gecko_installer_workaround(FALSE
);