mshtml: Reimplement IHTMLStyle::get_backgroundPositionY using background-position...
[wine] / dlls / mshtml / persist.c
1 /*
2  * Copyright 2005 Jacek Caban
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 "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 #define NONAMELESSSTRUCT
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winuser.h"
31 #include "ole2.h"
32 #include "shlguid.h"
33 #include "idispids.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 #include "mshtml_private.h"
39 #include "htmlevent.h"
40 #include "resource.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
43
44 typedef struct {
45     task_t header;
46     HTMLDocumentObj *doc;
47     BOOL set_download;
48     LPOLESTR url;
49 } download_proc_task_t;
50
51 static BOOL use_gecko_script(LPCWSTR url)
52 {
53     static const WCHAR fileW[] = {'f','i','l','e',':'};
54     static const WCHAR aboutW[] = {'a','b','o','u','t',':'};
55     static const WCHAR resW[] = {'r','e','s',':'};
56
57     return strncmpiW(fileW, url, sizeof(fileW)/sizeof(WCHAR))
58         && strncmpiW(aboutW, url, sizeof(aboutW)/sizeof(WCHAR))
59         && strncmpiW(resW, url, sizeof(resW)/sizeof(WCHAR));
60 }
61
62 void set_current_mon(HTMLWindow *This, IMoniker *mon)
63 {
64     HRESULT hres;
65
66     if(This->mon) {
67         IMoniker_Release(This->mon);
68         This->mon = NULL;
69     }
70
71     if(This->url) {
72         CoTaskMemFree(This->url);
73         This->url = NULL;
74     }
75
76     if(!mon)
77         return;
78
79     IMoniker_AddRef(mon);
80     This->mon = mon;
81
82     hres = IMoniker_GetDisplayName(mon, NULL, NULL, &This->url);
83     if(FAILED(hres))
84         WARN("GetDisplayName failed: %08x\n", hres);
85
86     set_script_mode(This, use_gecko_script(This->url) ? SCRIPTMODE_GECKO : SCRIPTMODE_ACTIVESCRIPT);
87 }
88
89 static void set_progress_proc(task_t *_task)
90 {
91     docobj_task_t *task = (docobj_task_t*)_task;
92     IOleCommandTarget *olecmd = NULL;
93     HTMLDocumentObj *doc = task->doc;
94     HRESULT hres;
95
96     TRACE("(%p)\n", doc);
97
98     if(doc->client)
99         IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
100
101     if(olecmd) {
102         VARIANT progress_max, progress;
103
104         V_VT(&progress_max) = VT_I4;
105         V_I4(&progress_max) = 0; /* FIXME */
106         IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETPROGRESSMAX, OLECMDEXECOPT_DONTPROMPTUSER,
107                                &progress_max, NULL);
108
109         V_VT(&progress) = VT_I4;
110         V_I4(&progress) = 0; /* FIXME */
111         IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETPROGRESSPOS, OLECMDEXECOPT_DONTPROMPTUSER,
112                                &progress, NULL);
113         IOleCommandTarget_Release(olecmd);
114     }
115
116     if(doc->usermode == EDITMODE && doc->hostui) {
117         DOCHOSTUIINFO hostinfo;
118
119         memset(&hostinfo, 0, sizeof(DOCHOSTUIINFO));
120         hostinfo.cbSize = sizeof(DOCHOSTUIINFO);
121         hres = IDocHostUIHandler_GetHostInfo(doc->hostui, &hostinfo);
122         if(SUCCEEDED(hres))
123             /* FIXME: use hostinfo */
124             TRACE("hostinfo = {%u %08x %08x %s %s}\n",
125                     hostinfo.cbSize, hostinfo.dwFlags, hostinfo.dwDoubleClick,
126                     debugstr_w(hostinfo.pchHostCss), debugstr_w(hostinfo.pchHostNS));
127     }
128 }
129
130 static void set_downloading_proc(task_t *_task)
131 {
132     download_proc_task_t *task = (download_proc_task_t*)_task;
133     HTMLDocumentObj *doc = task->doc;
134     IOleCommandTarget *olecmd;
135     HRESULT hres;
136
137     TRACE("(%p)\n", doc);
138
139     set_statustext(doc, IDS_STATUS_DOWNLOADINGFROM, task->url);
140     CoTaskMemFree(task->url);
141
142     if(!doc->client)
143         return;
144
145     if(task->set_download) {
146         hres = IOleClientSite_QueryInterface(doc->client, &IID_IOleCommandTarget, (void**)&olecmd);
147         if(SUCCEEDED(hres)) {
148             VARIANT var;
149
150             V_VT(&var) = VT_I4;
151             V_I4(&var) = 1;
152
153             IOleCommandTarget_Exec(olecmd, NULL, OLECMDID_SETDOWNLOADSTATE,
154                     OLECMDEXECOPT_DONTPROMPTUSER, &var, NULL);
155             IOleCommandTarget_Release(olecmd);
156         }
157
158         doc->download_state = 1;
159     }
160
161     if(doc->view_sink)
162         IAdviseSink_OnViewChange(doc->view_sink, DVASPECT_CONTENT, -1);
163
164     if(doc->hostui) {
165         IDropTarget *drop_target = NULL;
166
167         hres = IDocHostUIHandler_GetDropTarget(doc->hostui, NULL /* FIXME */, &drop_target);
168         if(drop_target) {
169             FIXME("Use IDropTarget\n");
170             IDropTarget_Release(drop_target);
171         }
172     }
173 }
174
175 HRESULT set_moniker(HTMLDocument *This, IMoniker *mon, IBindCtx *pibc, nsChannelBSC *async_bsc, BOOL set_download)
176 {
177     nsChannelBSC *bscallback;
178     docobj_task_t *task;
179     download_proc_task_t *download_task;
180     nsWineURI *nsuri;
181     LPOLESTR url;
182     HRESULT hres;
183
184     hres = IMoniker_GetDisplayName(mon, pibc, NULL, &url);
185     if(FAILED(hres)) {
186         WARN("GetDiaplayName failed: %08x\n", hres);
187         return hres;
188     }
189
190     TRACE("got url: %s\n", debugstr_w(url));
191
192     if(This->doc_obj->client) {
193         VARIANT silent, offline;
194
195         hres = get_client_disp_property(This->doc_obj->client, DISPID_AMBIENT_SILENT, &silent);
196         if(SUCCEEDED(hres)) {
197             if(V_VT(&silent) != VT_BOOL)
198                 WARN("V_VT(silent) = %d\n", V_VT(&silent));
199             else if(V_BOOL(&silent))
200                 FIXME("silent == true\n");
201         }
202
203         hres = get_client_disp_property(This->doc_obj->client,
204                 DISPID_AMBIENT_OFFLINEIFNOTCONNECTED, &offline);
205         if(SUCCEEDED(hres)) {
206             if(V_VT(&offline) != VT_BOOL)
207                 WARN("V_VT(offline) = %d\n", V_VT(&offline));
208             else if(V_BOOL(&offline))
209                 FIXME("offline == true\n");
210         }
211     }
212
213     if(This->window->mon) {
214         update_doc(This, UPDATE_TITLE|UPDATE_UI);
215     }else {
216         update_doc(This, UPDATE_TITLE);
217         set_current_mon(This->window, mon);
218     }
219
220     set_ready_state(This->window, READYSTATE_LOADING);
221
222     if(This->doc_obj->client) {
223         IOleCommandTarget *cmdtrg = NULL;
224
225         hres = IOleClientSite_QueryInterface(This->doc_obj->client, &IID_IOleCommandTarget,
226                 (void**)&cmdtrg);
227         if(SUCCEEDED(hres)) {
228             VARIANT var, out;
229
230             if(!async_bsc) {
231                 V_VT(&var) = VT_I4;
232                 V_I4(&var) = 0;
233                 IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 37, 0, &var, NULL);
234             }else {
235                 V_VT(&var) = VT_UNKNOWN;
236                 V_UNKNOWN(&var) = (IUnknown*)&This->window->IHTMLWindow2_iface;
237                 V_VT(&out) = VT_EMPTY;
238                 hres = IOleCommandTarget_Exec(cmdtrg, &CGID_ShellDocView, 63, 0, &var, &out);
239                 if(SUCCEEDED(hres))
240                     VariantClear(&out);
241             }
242
243             IOleCommandTarget_Release(cmdtrg);
244         }
245     }
246
247     hres = create_doc_uri(This->window, url, &nsuri);
248
249     if(SUCCEEDED(hres))
250     {
251         if(async_bsc) {
252             bscallback = async_bsc;
253         }else {
254             hres = create_channelbsc(mon, NULL, NULL, 0, &bscallback);
255         }
256     }
257
258     if(SUCCEEDED(hres))
259     {
260         remove_target_tasks(This->task_magic);
261         abort_document_bindings(This->doc_node);
262
263         hres = load_nsuri(This->window, nsuri, bscallback, LOAD_INITIAL_DOCUMENT_URI);
264         nsISupports_Release((nsISupports*)nsuri); /* FIXME */
265         if(SUCCEEDED(hres))
266             set_window_bscallback(This->window, bscallback);
267         if(bscallback != async_bsc)
268             IUnknown_Release((IUnknown*)bscallback);
269     }
270
271     if(FAILED(hres))
272     {
273         CoTaskMemFree(url);
274         return hres;
275     }
276
277     HTMLDocument_LockContainer(This->doc_obj, TRUE);
278
279     if(This->doc_obj->frame) {
280         task = heap_alloc(sizeof(docobj_task_t));
281         task->doc = This->doc_obj;
282         push_task(&task->header, set_progress_proc, This->doc_obj->basedoc.task_magic);
283     }
284
285     download_task = heap_alloc(sizeof(download_proc_task_t));
286     download_task->doc = This->doc_obj;
287     download_task->set_download = set_download;
288     download_task->url = url;
289     push_task(&download_task->header, set_downloading_proc, This->doc_obj->basedoc.task_magic);
290
291     return S_OK;
292 }
293
294 void set_ready_state(HTMLWindow *window, READYSTATE readystate)
295 {
296     window->readystate = readystate;
297
298     if(window->doc_obj && window->doc_obj->basedoc.window == window)
299         call_property_onchanged(&window->doc_obj->basedoc.cp_propnotif, DISPID_READYSTATE);
300
301     fire_event(window->doc, EVENTID_READYSTATECHANGE, FALSE, window->doc->node.nsnode, NULL);
302
303     if(window->frame_element)
304         fire_event(window->frame_element->element.node.doc, EVENTID_READYSTATECHANGE,
305                    TRUE, window->frame_element->element.node.nsnode, NULL);
306 }
307
308 static HRESULT get_doc_string(HTMLDocumentNode *This, char **str)
309 {
310     nsIDOMNode *nsnode;
311     LPCWSTR strw;
312     nsAString nsstr;
313     nsresult nsres;
314
315     if(!This->nsdoc) {
316         WARN("NULL nsdoc\n");
317         return E_UNEXPECTED;
318     }
319
320     nsres = nsIDOMHTMLDocument_QueryInterface(This->nsdoc, &IID_nsIDOMNode, (void**)&nsnode);
321     if(NS_FAILED(nsres)) {
322         ERR("Could not get nsIDOMNode failed: %08x\n", nsres);
323         return E_FAIL;
324     }
325
326     nsAString_Init(&nsstr, NULL);
327     nsnode_to_nsstring(nsnode, &nsstr);
328     nsIDOMNode_Release(nsnode);
329
330     nsAString_GetData(&nsstr, &strw);
331     TRACE("%s\n", debugstr_w(strw));
332
333     *str = heap_strdupWtoA(strw);
334
335     nsAString_Finish(&nsstr);
336
337     return S_OK;
338 }
339
340
341 /**********************************************************
342  * IPersistMoniker implementation
343  */
344
345 static inline HTMLDocument *impl_from_IPersistMoniker(IPersistMoniker *iface)
346 {
347     return CONTAINING_RECORD(iface, HTMLDocument, IPersistMoniker_iface);
348 }
349
350 static HRESULT WINAPI PersistMoniker_QueryInterface(IPersistMoniker *iface, REFIID riid, void **ppv)
351 {
352     HTMLDocument *This = impl_from_IPersistMoniker(iface);
353     return htmldoc_query_interface(This, riid, ppv);
354 }
355
356 static ULONG WINAPI PersistMoniker_AddRef(IPersistMoniker *iface)
357 {
358     HTMLDocument *This = impl_from_IPersistMoniker(iface);
359     return htmldoc_addref(This);
360 }
361
362 static ULONG WINAPI PersistMoniker_Release(IPersistMoniker *iface)
363 {
364     HTMLDocument *This = impl_from_IPersistMoniker(iface);
365     return htmldoc_release(This);
366 }
367
368 static HRESULT WINAPI PersistMoniker_GetClassID(IPersistMoniker *iface, CLSID *pClassID)
369 {
370     HTMLDocument *This = impl_from_IPersistMoniker(iface);
371     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
372 }
373
374 static HRESULT WINAPI PersistMoniker_IsDirty(IPersistMoniker *iface)
375 {
376     HTMLDocument *This = impl_from_IPersistMoniker(iface);
377
378     TRACE("(%p)\n", This);
379
380     return IPersistStreamInit_IsDirty(&This->IPersistStreamInit_iface);
381 }
382
383 static HRESULT WINAPI PersistMoniker_Load(IPersistMoniker *iface, BOOL fFullyAvailable,
384         IMoniker *pimkName, LPBC pibc, DWORD grfMode)
385 {
386     HTMLDocument *This = impl_from_IPersistMoniker(iface);
387     HRESULT hres;
388
389     TRACE("(%p)->(%x %p %p %08x)\n", This, fFullyAvailable, pimkName, pibc, grfMode);
390
391     if(pibc) {
392         IUnknown *unk = NULL;
393
394         /* FIXME:
395          * Use params:
396          * "__PrecreatedObject"
397          * "BIND_CONTEXT_PARAM"
398          * "__HTMLLOADOPTIONS"
399          * "__DWNBINDINFO"
400          * "URL Context"
401          * "_ITransData_Object_"
402          * "_EnumFORMATETC_"
403          */
404
405         IBindCtx_GetObjectParam(pibc, (LPOLESTR)SZ_HTML_CLIENTSITE_OBJECTPARAM, &unk);
406         if(unk) {
407             IOleClientSite *client = NULL;
408
409             hres = IUnknown_QueryInterface(unk, &IID_IOleClientSite, (void**)&client);
410             if(SUCCEEDED(hres)) {
411                 TRACE("Got client site %p\n", client);
412                 IOleObject_SetClientSite(&This->IOleObject_iface, client);
413                 IOleClientSite_Release(client);
414             }
415
416             IUnknown_Release(unk);
417         }
418     }
419
420     hres = set_moniker(This, pimkName, pibc, NULL, TRUE);
421     if(FAILED(hres))
422         return hres;
423
424     return start_binding(This->window, NULL, (BSCallback*)This->window->bscallback, pibc);
425 }
426
427 static HRESULT WINAPI PersistMoniker_Save(IPersistMoniker *iface, IMoniker *pimkName,
428         LPBC pbc, BOOL fRemember)
429 {
430     HTMLDocument *This = impl_from_IPersistMoniker(iface);
431     FIXME("(%p)->(%p %p %x)\n", This, pimkName, pbc, fRemember);
432     return E_NOTIMPL;
433 }
434
435 static HRESULT WINAPI PersistMoniker_SaveCompleted(IPersistMoniker *iface, IMoniker *pimkName, LPBC pibc)
436 {
437     HTMLDocument *This = impl_from_IPersistMoniker(iface);
438     FIXME("(%p)->(%p %p)\n", This, pimkName, pibc);
439     return E_NOTIMPL;
440 }
441
442 static HRESULT WINAPI PersistMoniker_GetCurMoniker(IPersistMoniker *iface, IMoniker **ppimkName)
443 {
444     HTMLDocument *This = impl_from_IPersistMoniker(iface);
445
446     TRACE("(%p)->(%p)\n", This, ppimkName);
447
448     if(!This->window || !This->window->mon)
449         return E_UNEXPECTED;
450
451     IMoniker_AddRef(This->window->mon);
452     *ppimkName = This->window->mon;
453     return S_OK;
454 }
455
456 static const IPersistMonikerVtbl PersistMonikerVtbl = {
457     PersistMoniker_QueryInterface,
458     PersistMoniker_AddRef,
459     PersistMoniker_Release,
460     PersistMoniker_GetClassID,
461     PersistMoniker_IsDirty,
462     PersistMoniker_Load,
463     PersistMoniker_Save,
464     PersistMoniker_SaveCompleted,
465     PersistMoniker_GetCurMoniker
466 };
467
468 /**********************************************************
469  * IMonikerProp implementation
470  */
471
472 static inline HTMLDocument *impl_from_IMonikerProp(IMonikerProp *iface)
473 {
474     return CONTAINING_RECORD(iface, HTMLDocument, IMonikerProp_iface);
475 }
476
477 static HRESULT WINAPI MonikerProp_QueryInterface(IMonikerProp *iface, REFIID riid, void **ppv)
478 {
479     HTMLDocument *This = impl_from_IMonikerProp(iface);
480     return htmldoc_query_interface(This, riid, ppv);
481 }
482
483 static ULONG WINAPI MonikerProp_AddRef(IMonikerProp *iface)
484 {
485     HTMLDocument *This = impl_from_IMonikerProp(iface);
486     return htmldoc_addref(This);
487 }
488
489 static ULONG WINAPI MonikerProp_Release(IMonikerProp *iface)
490 {
491     HTMLDocument *This = impl_from_IMonikerProp(iface);
492     return htmldoc_release(This);
493 }
494
495 static HRESULT WINAPI MonikerProp_PutProperty(IMonikerProp *iface, MONIKERPROPERTY mkp, LPCWSTR val)
496 {
497     HTMLDocument *This = impl_from_IMonikerProp(iface);
498
499     TRACE("(%p)->(%d %s)\n", This, mkp, debugstr_w(val));
500
501     switch(mkp) {
502     case MIMETYPEPROP:
503         heap_free(This->doc_obj->mime);
504         This->doc_obj->mime = heap_strdupW(val);
505         break;
506
507     case CLASSIDPROP:
508         break;
509
510     default:
511         FIXME("mkp %d\n", mkp);
512         return E_NOTIMPL;
513     }
514
515     return S_OK;
516 }
517
518 static const IMonikerPropVtbl MonikerPropVtbl = {
519     MonikerProp_QueryInterface,
520     MonikerProp_AddRef,
521     MonikerProp_Release,
522     MonikerProp_PutProperty
523 };
524
525 /**********************************************************
526  * IPersistFile implementation
527  */
528
529 static inline HTMLDocument *impl_from_IPersistFile(IPersistFile *iface)
530 {
531     return CONTAINING_RECORD(iface, HTMLDocument, IPersistFile_iface);
532 }
533
534 static HRESULT WINAPI PersistFile_QueryInterface(IPersistFile *iface, REFIID riid, void **ppv)
535 {
536     HTMLDocument *This = impl_from_IPersistFile(iface);
537     return htmldoc_query_interface(This, riid, ppv);
538 }
539
540 static ULONG WINAPI PersistFile_AddRef(IPersistFile *iface)
541 {
542     HTMLDocument *This = impl_from_IPersistFile(iface);
543     return htmldoc_addref(This);
544 }
545
546 static ULONG WINAPI PersistFile_Release(IPersistFile *iface)
547 {
548     HTMLDocument *This = impl_from_IPersistFile(iface);
549     return htmldoc_release(This);
550 }
551
552 static HRESULT WINAPI PersistFile_GetClassID(IPersistFile *iface, CLSID *pClassID)
553 {
554     HTMLDocument *This = impl_from_IPersistFile(iface);
555
556     TRACE("(%p)->(%p)\n", This, pClassID);
557
558     if(!pClassID)
559         return E_INVALIDARG;
560
561     *pClassID = CLSID_HTMLDocument;
562     return S_OK;
563 }
564
565 static HRESULT WINAPI PersistFile_IsDirty(IPersistFile *iface)
566 {
567     HTMLDocument *This = impl_from_IPersistFile(iface);
568
569     TRACE("(%p)\n", This);
570
571     return IPersistStreamInit_IsDirty(&This->IPersistStreamInit_iface);
572 }
573
574 static HRESULT WINAPI PersistFile_Load(IPersistFile *iface, LPCOLESTR pszFileName, DWORD dwMode)
575 {
576     HTMLDocument *This = impl_from_IPersistFile(iface);
577     FIXME("(%p)->(%s %08x)\n", This, debugstr_w(pszFileName), dwMode);
578     return E_NOTIMPL;
579 }
580
581 static HRESULT WINAPI PersistFile_Save(IPersistFile *iface, LPCOLESTR pszFileName, BOOL fRemember)
582 {
583     HTMLDocument *This = impl_from_IPersistFile(iface);
584     char *str;
585     DWORD written=0;
586     HANDLE file;
587     HRESULT hres;
588
589     TRACE("(%p)->(%s %x)\n", This, debugstr_w(pszFileName), fRemember);
590
591     file = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
592                        FILE_ATTRIBUTE_NORMAL, NULL);
593     if(file == INVALID_HANDLE_VALUE) {
594         WARN("Could not create file: %u\n", GetLastError());
595         return E_FAIL;
596     }
597
598     hres = get_doc_string(This->doc_node, &str);
599     if(SUCCEEDED(hres))
600         WriteFile(file, str, strlen(str), &written, NULL);
601
602     CloseHandle(file);
603     return hres;
604 }
605
606 static HRESULT WINAPI PersistFile_SaveCompleted(IPersistFile *iface, LPCOLESTR pszFileName)
607 {
608     HTMLDocument *This = impl_from_IPersistFile(iface);
609     FIXME("(%p)->(%s)\n", This, debugstr_w(pszFileName));
610     return E_NOTIMPL;
611 }
612
613 static HRESULT WINAPI PersistFile_GetCurFile(IPersistFile *iface, LPOLESTR *pszFileName)
614 {
615     HTMLDocument *This = impl_from_IPersistFile(iface);
616     FIXME("(%p)->(%p)\n", This, pszFileName);
617     return E_NOTIMPL;
618 }
619
620 static const IPersistFileVtbl PersistFileVtbl = {
621     PersistFile_QueryInterface,
622     PersistFile_AddRef,
623     PersistFile_Release,
624     PersistFile_GetClassID,
625     PersistFile_IsDirty,
626     PersistFile_Load,
627     PersistFile_Save,
628     PersistFile_SaveCompleted,
629     PersistFile_GetCurFile
630 };
631
632 static inline HTMLDocument *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
633 {
634     return CONTAINING_RECORD(iface, HTMLDocument, IPersistStreamInit_iface);
635 }
636
637 static HRESULT WINAPI PersistStreamInit_QueryInterface(IPersistStreamInit *iface,
638                                                        REFIID riid, void **ppv)
639 {
640     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
641     return htmldoc_query_interface(This, riid, ppv);
642 }
643
644 static ULONG WINAPI PersistStreamInit_AddRef(IPersistStreamInit *iface)
645 {
646     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
647     return htmldoc_addref(This);
648 }
649
650 static ULONG WINAPI PersistStreamInit_Release(IPersistStreamInit *iface)
651 {
652     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
653     return htmldoc_release(This);
654 }
655
656 static HRESULT WINAPI PersistStreamInit_GetClassID(IPersistStreamInit *iface, CLSID *pClassID)
657 {
658     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
659     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
660 }
661
662 static HRESULT WINAPI PersistStreamInit_IsDirty(IPersistStreamInit *iface)
663 {
664     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
665
666     TRACE("(%p)\n", This);
667
668     if(This->doc_obj->usermode == EDITMODE)
669         return editor_is_dirty(This);
670
671     return S_FALSE;
672 }
673
674 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, LPSTREAM pStm)
675 {
676     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
677     IMoniker *mon;
678     HRESULT hres;
679
680     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
681
682     TRACE("(%p)->(%p)\n", This, pStm);
683
684     hres = CreateURLMoniker(NULL, about_blankW, &mon);
685     if(FAILED(hres)) {
686         WARN("CreateURLMoniker failed: %08x\n", hres);
687         return hres;
688     }
689
690     hres = set_moniker(This, mon, NULL, NULL, TRUE);
691     IMoniker_Release(mon);
692     if(FAILED(hres))
693         return hres;
694
695     return channelbsc_load_stream(This->window->bscallback, pStm);
696 }
697
698 static HRESULT WINAPI PersistStreamInit_Save(IPersistStreamInit *iface, LPSTREAM pStm,
699                                              BOOL fClearDirty)
700 {
701     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
702     char *str;
703     DWORD written=0;
704     HRESULT hres;
705
706     TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
707
708     hres = get_doc_string(This->doc_node, &str);
709     if(FAILED(hres))
710         return hres;
711
712     hres = IStream_Write(pStm, str, strlen(str), &written);
713     if(FAILED(hres))
714         FIXME("Write failed: %08x\n", hres);
715
716     heap_free(str);
717
718     if(fClearDirty)
719         set_dirty(This, VARIANT_FALSE);
720
721     return S_OK;
722 }
723
724 static HRESULT WINAPI PersistStreamInit_GetSizeMax(IPersistStreamInit *iface,
725                                                    ULARGE_INTEGER *pcbSize)
726 {
727     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
728     FIXME("(%p)->(%p)\n", This, pcbSize);
729     return E_NOTIMPL;
730 }
731
732 static HRESULT WINAPI PersistStreamInit_InitNew(IPersistStreamInit *iface)
733 {
734     HTMLDocument *This = impl_from_IPersistStreamInit(iface);
735     IMoniker *mon;
736     HRESULT hres;
737
738     static const WCHAR about_blankW[] = {'a','b','o','u','t',':','b','l','a','n','k',0};
739
740     TRACE("(%p)\n", This);
741
742     hres = CreateURLMoniker(NULL, about_blankW, &mon);
743     if(FAILED(hres)) {
744         WARN("CreateURLMoniker failed: %08x\n", hres);
745         return hres;
746     }
747
748     hres = set_moniker(This, mon, NULL, NULL, FALSE);
749     IMoniker_Release(mon);
750     if(FAILED(hres))
751         return hres;
752
753     return channelbsc_load_stream(This->window->bscallback, NULL);
754 }
755
756 static const IPersistStreamInitVtbl PersistStreamInitVtbl = {
757     PersistStreamInit_QueryInterface,
758     PersistStreamInit_AddRef,
759     PersistStreamInit_Release,
760     PersistStreamInit_GetClassID,
761     PersistStreamInit_IsDirty,
762     PersistStreamInit_Load,
763     PersistStreamInit_Save,
764     PersistStreamInit_GetSizeMax,
765     PersistStreamInit_InitNew
766 };
767
768 /**********************************************************
769  * IPersistHistory implementation
770  */
771
772 static inline HTMLDocument *impl_from_IPersistHistory(IPersistHistory *iface)
773 {
774     return CONTAINING_RECORD(iface, HTMLDocument, IPersistHistory_iface);
775 }
776
777 static HRESULT WINAPI PersistHistory_QueryInterface(IPersistHistory *iface, REFIID riid, void **ppv)
778 {
779     HTMLDocument *This = impl_from_IPersistHistory(iface);
780     return htmldoc_query_interface(This, riid, ppv);
781 }
782
783 static ULONG WINAPI PersistHistory_AddRef(IPersistHistory *iface)
784 {
785     HTMLDocument *This = impl_from_IPersistHistory(iface);
786     return htmldoc_addref(This);
787 }
788
789 static ULONG WINAPI PersistHistory_Release(IPersistHistory *iface)
790 {
791     HTMLDocument *This = impl_from_IPersistHistory(iface);
792     return htmldoc_release(This);
793 }
794
795 static HRESULT WINAPI PersistHistory_GetClassID(IPersistHistory *iface, CLSID *pClassID)
796 {
797     HTMLDocument *This = impl_from_IPersistHistory(iface);
798     return IPersist_GetClassID(&This->IPersistFile_iface, pClassID);
799 }
800
801 static HRESULT WINAPI PersistHistory_LoadHistory(IPersistHistory *iface, IStream *pStream, IBindCtx *pbc)
802 {
803     HTMLDocument *This = impl_from_IPersistHistory(iface);
804     FIXME("(%p)->(%p %p)\n", This, pStream, pbc);
805     return E_NOTIMPL;
806 }
807
808 static HRESULT WINAPI PersistHistory_SaveHistory(IPersistHistory *iface, IStream *pStream)
809 {
810     HTMLDocument *This = impl_from_IPersistHistory(iface);
811     FIXME("(%p)->(%p)\n", This, pStream);
812     return E_NOTIMPL;
813 }
814
815 static HRESULT WINAPI PersistHistory_SetPositionCookie(IPersistHistory *iface, DWORD dwPositioncookie)
816 {
817     HTMLDocument *This = impl_from_IPersistHistory(iface);
818     FIXME("(%p)->(%x)\n", This, dwPositioncookie);
819     return E_NOTIMPL;
820 }
821
822 static HRESULT WINAPI PersistHistory_GetPositionCookie(IPersistHistory *iface, DWORD *pdwPositioncookie)
823 {
824     HTMLDocument *This = impl_from_IPersistHistory(iface);
825     FIXME("(%p)->(%p)\n", This, pdwPositioncookie);
826     return E_NOTIMPL;
827 }
828
829 static const IPersistHistoryVtbl PersistHistoryVtbl = {
830     PersistHistory_QueryInterface,
831     PersistHistory_AddRef,
832     PersistHistory_Release,
833     PersistHistory_GetClassID,
834     PersistHistory_LoadHistory,
835     PersistHistory_SaveHistory,
836     PersistHistory_SetPositionCookie,
837     PersistHistory_GetPositionCookie
838 };
839
840 void HTMLDocument_Persist_Init(HTMLDocument *This)
841 {
842     This->IPersistMoniker_iface.lpVtbl = &PersistMonikerVtbl;
843     This->IPersistFile_iface.lpVtbl = &PersistFileVtbl;
844     This->IMonikerProp_iface.lpVtbl = &MonikerPropVtbl;
845     This->IPersistStreamInit_iface.lpVtbl = &PersistStreamInitVtbl;
846     This->IPersistHistory_iface.lpVtbl = &PersistHistoryVtbl;
847 }