uxtheme: Fixed the todo blocks in the IsThemed tests when theming is inactive.
[wine] / dlls / oleaut32 / olepicture.c
1 /*
2  * OLE Picture object
3  *
4  * Implementation of OLE IPicture and related interfaces
5  *
6  * Copyright 2000 Huw D M Davies for CodeWeavers.
7  * Copyright 2001 Marcus Meissner
8  * Copyright 2008 Kirill K. Smirnov
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  * BUGS
25  *
26  * Support PICTYPE_BITMAP and PICTYPE_ICON, although only bitmaps very well..
27  * Lots of methods are just stubs.
28  *
29  *
30  * NOTES (or things that msdn doesn't tell you)
31  *
32  * The width and height properties are returned in HIMETRIC units (0.01mm)
33  * IPicture::Render also uses these to select a region of the src picture.
34  * A bitmap's size is converted into these units by using the screen resolution
35  * thus an 8x8 bitmap on a 96dpi screen has a size of 212x212 (8/96 * 2540).
36  *
37  */
38
39 #include "config.h"
40 #include "wine/port.h"
41
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <stdarg.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 #ifdef SONAME_LIBJPEG
50 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
51 #define XMD_H
52 #define UINT8 JPEG_UINT8
53 #define UINT16 JPEG_UINT16
54 #define boolean jpeg_boolean
55 # include <jpeglib.h>
56 #undef UINT8
57 #undef UINT16
58 #undef boolean
59 #endif
60
61 #ifdef HAVE_PNG_H
62 #include <png.h>
63 #endif
64
65 /* Must be before wine includes, the header has things conflicting with
66  * WINE headers.
67  */
68 #define COBJMACROS
69 #define NONAMELESSUNION
70 #define NONAMELESSSTRUCT
71
72 #include "winerror.h"
73 #include "windef.h"
74 #include "winbase.h"
75 #include "wingdi.h"
76 #include "winuser.h"
77 #include "ole2.h"
78 #include "olectl.h"
79 #include "oleauto.h"
80 #include "connpt.h"
81 #include "urlmon.h"
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
84
85 #include "wine/wingdi16.h"
86
87 #include "ungif.h"
88
89 WINE_DEFAULT_DEBUG_CHANNEL(ole);
90
91 #include "pshpack1.h"
92
93 /* Header for Aldus Placable Metafiles - a standard metafile follows */
94 typedef struct _APM_HEADER
95 {
96     DWORD key;
97     WORD handle;
98     SHORT left;
99     SHORT top;
100     SHORT right;
101     SHORT bottom;
102     WORD inch;
103     DWORD reserved;
104     WORD checksum;
105 } APM_HEADER;
106
107 typedef struct {
108     BYTE bWidth;
109     BYTE bHeight;
110     BYTE bColorCount;
111     BYTE bReserved;
112     WORD xHotspot;
113     WORD yHotspot;
114     DWORD dwDIBSize;
115     DWORD dwDIBOffset;
116 } CURSORICONFILEDIRENTRY;
117
118 typedef struct
119 {
120     WORD                idReserved;
121     WORD                idType;
122     WORD                idCount;
123     CURSORICONFILEDIRENTRY  idEntries[1];
124 } CURSORICONFILEDIR;
125
126 #include "poppack.h"
127
128 /*************************************************************************
129  *  Declaration of implementation class
130  */
131
132 typedef struct OLEPictureImpl {
133
134   /*
135    * IPicture handles IUnknown
136    */
137
138     const IPictureVtbl       *lpVtbl;
139     const IDispatchVtbl      *lpvtblIDispatch;
140     const IPersistStreamVtbl *lpvtblIPersistStream;
141     const IConnectionPointContainerVtbl *lpvtblIConnectionPointContainer;
142
143   /* Object reference count */
144     LONG ref;
145
146   /* We own the object and must destroy it ourselves */
147     BOOL fOwn;
148
149   /* Picture description */
150     PICTDESC desc;
151
152   /* These are the pixel size of a bitmap */
153     DWORD origWidth;
154     DWORD origHeight;
155
156   /* And these are the size of the picture converted into HIMETRIC units */
157     OLE_XSIZE_HIMETRIC himetricWidth;
158     OLE_YSIZE_HIMETRIC himetricHeight;
159
160     IConnectionPoint *pCP;
161
162     BOOL keepOrigFormat;
163     HDC hDCCur;
164
165   /* Bitmap transparency mask */
166     HBITMAP hbmMask;
167     HBITMAP hbmXor;
168     COLORREF rgbTrans;
169
170   /* data */
171     void* data;
172     int datalen;
173     BOOL bIsDirty;                  /* Set to TRUE if picture has changed */
174     unsigned int loadtime_magic;    /* If a length header was found, saves value */
175     unsigned int loadtime_format;   /* for PICTYPE_BITMAP only, keeps track of image format (GIF/BMP/JPEG) */
176 } OLEPictureImpl;
177
178 /*
179  * Macros to retrieve pointer to IUnknown (IPicture) from the other VTables.
180  */
181
182 static inline OLEPictureImpl *impl_from_IDispatch( IDispatch *iface )
183 {
184     return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIDispatch));
185 }
186
187 static inline OLEPictureImpl *impl_from_IPersistStream( IPersistStream *iface )
188 {
189     return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIPersistStream));
190 }
191
192 static inline OLEPictureImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
193 {
194     return (OLEPictureImpl *)((char*)iface - FIELD_OFFSET(OLEPictureImpl, lpvtblIConnectionPointContainer));
195 }
196
197 /*
198  * Predeclare VTables.  They get initialized at the end.
199  */
200 static const IPictureVtbl OLEPictureImpl_VTable;
201 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable;
202 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable;
203 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable;
204
205 /***********************************************************************
206  * Implementation of the OLEPictureImpl class.
207  */
208
209 static void OLEPictureImpl_SetBitmap(OLEPictureImpl*This) {
210   BITMAP bm;
211   HDC hdcRef;
212
213   TRACE("bitmap handle %p\n", This->desc.u.bmp.hbitmap);
214   if(GetObjectA(This->desc.u.bmp.hbitmap, sizeof(bm), &bm) != sizeof(bm)) {
215     ERR("GetObject fails\n");
216     return;
217   }
218   This->origWidth = bm.bmWidth;
219   This->origHeight = bm.bmHeight;
220   /* The width and height are stored in HIMETRIC units (0.01 mm),
221      so we take our pixel width divide by pixels per inch and
222      multiply by 25.4 * 100 */
223   /* Should we use GetBitmapDimension if available? */
224   hdcRef = CreateCompatibleDC(0);
225   This->himetricWidth =(bm.bmWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
226   This->himetricHeight=(bm.bmHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
227   DeleteDC(hdcRef);
228 }
229
230 static void OLEPictureImpl_SetIcon(OLEPictureImpl * This)
231 {
232     ICONINFO infoIcon;
233
234     TRACE("icon handle %p\n", This->desc.u.icon.hicon);
235     if (GetIconInfo(This->desc.u.icon.hicon, &infoIcon)) {
236         HDC hdcRef;
237         BITMAP bm;
238
239         TRACE("bitmap handle for icon is %p\n", infoIcon.hbmColor);
240         if(GetObjectA(infoIcon.hbmColor ? infoIcon.hbmColor : infoIcon.hbmMask, sizeof(bm), &bm) != sizeof(bm)) {
241             ERR("GetObject fails on icon bitmap\n");
242             return;
243         }
244
245         This->origWidth = bm.bmWidth;
246         This->origHeight = infoIcon.hbmColor ? bm.bmHeight : bm.bmHeight / 2;
247         /* see comment on HIMETRIC on OLEPictureImpl_SetBitmap() */
248         hdcRef = GetDC(0);
249         This->himetricWidth = (This->origWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
250         This->himetricHeight= (This->origHeight *2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
251         ReleaseDC(0, hdcRef);
252
253         DeleteObject(infoIcon.hbmMask);
254         if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
255     } else {
256         ERR("GetIconInfo() fails on icon %p\n", This->desc.u.icon.hicon);
257     }
258 }
259
260 /************************************************************************
261  * OLEPictureImpl_Construct
262  *
263  * This method will construct a new instance of the OLEPictureImpl
264  * class.
265  *
266  * The caller of this method must release the object when it's
267  * done with it.
268  */
269 static OLEPictureImpl* OLEPictureImpl_Construct(LPPICTDESC pictDesc, BOOL fOwn)
270 {
271   OLEPictureImpl* newObject = 0;
272
273   if (pictDesc)
274       TRACE("(%p) type = %d\n", pictDesc, pictDesc->picType);
275
276   /*
277    * Allocate space for the object.
278    */
279   newObject = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(OLEPictureImpl));
280
281   if (newObject==0)
282     return newObject;
283
284   /*
285    * Initialize the virtual function table.
286    */
287   newObject->lpVtbl = &OLEPictureImpl_VTable;
288   newObject->lpvtblIDispatch = &OLEPictureImpl_IDispatch_VTable;
289   newObject->lpvtblIPersistStream = &OLEPictureImpl_IPersistStream_VTable;
290   newObject->lpvtblIConnectionPointContainer = &OLEPictureImpl_IConnectionPointContainer_VTable;
291
292   newObject->pCP = NULL;
293   CreateConnectionPoint((IUnknown*)newObject,&IID_IPropertyNotifySink,&newObject->pCP);
294   if (!newObject->pCP)
295   {
296     HeapFree(GetProcessHeap(), 0, newObject);
297     return NULL;
298   }
299
300   /*
301    * Start with one reference count. The caller of this function
302    * must release the interface pointer when it is done.
303    */
304   newObject->ref        = 1;
305   newObject->hDCCur     = 0;
306
307   newObject->fOwn       = fOwn;
308
309   /* dunno about original value */
310   newObject->keepOrigFormat = TRUE;
311
312   newObject->hbmMask = NULL;
313   newObject->hbmXor = NULL;
314   newObject->loadtime_magic = 0xdeadbeef;
315   newObject->loadtime_format = 0;
316   newObject->bIsDirty = FALSE;
317
318   if (pictDesc) {
319       newObject->desc = *pictDesc;
320
321       switch(pictDesc->picType) {
322       case PICTYPE_BITMAP:
323         OLEPictureImpl_SetBitmap(newObject);
324         break;
325
326       case PICTYPE_METAFILE:
327         TRACE("metafile handle %p\n", pictDesc->u.wmf.hmeta);
328         newObject->himetricWidth = pictDesc->u.wmf.xExt;
329         newObject->himetricHeight = pictDesc->u.wmf.yExt;
330         break;
331
332       case PICTYPE_NONE:
333         /* not sure what to do here */
334         newObject->himetricWidth = newObject->himetricHeight = 0;
335         break;
336
337       case PICTYPE_ICON:
338         OLEPictureImpl_SetIcon(newObject);
339         break;
340       case PICTYPE_ENHMETAFILE:
341       default:
342         FIXME("Unsupported type %d\n", pictDesc->picType);
343         newObject->himetricWidth = newObject->himetricHeight = 0;
344         break;
345       }
346   } else {
347       newObject->desc.picType = PICTYPE_UNINITIALIZED;
348   }
349
350   TRACE("returning %p\n", newObject);
351   return newObject;
352 }
353
354 /************************************************************************
355  * OLEPictureImpl_Destroy
356  *
357  * This method is called by the Release method when the reference
358  * count goes down to 0. It will free all resources used by
359  * this object.  */
360 static void OLEPictureImpl_Destroy(OLEPictureImpl* Obj)
361 {
362   TRACE("(%p)\n", Obj);
363
364   if (Obj->pCP)
365     IConnectionPoint_Release(Obj->pCP);
366
367   if(Obj->fOwn) { /* We need to destroy the picture */
368     switch(Obj->desc.picType) {
369     case PICTYPE_BITMAP:
370       DeleteObject(Obj->desc.u.bmp.hbitmap);
371       if (Obj->hbmMask != NULL) DeleteObject(Obj->hbmMask);
372       if (Obj->hbmXor != NULL) DeleteObject(Obj->hbmXor);
373       break;
374     case PICTYPE_METAFILE:
375       DeleteMetaFile(Obj->desc.u.wmf.hmeta);
376       break;
377     case PICTYPE_ICON:
378       DestroyIcon(Obj->desc.u.icon.hicon);
379       break;
380     case PICTYPE_ENHMETAFILE:
381       DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
382       break;
383     case PICTYPE_NONE:
384     case PICTYPE_UNINITIALIZED:
385       /* Nothing to do */
386       break;
387     default:
388       FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
389       break;
390     }
391   }
392   HeapFree(GetProcessHeap(), 0, Obj->data);
393   HeapFree(GetProcessHeap(), 0, Obj);
394 }
395
396
397 /************************************************************************
398  * OLEPictureImpl_AddRef (IUnknown)
399  *
400  * See Windows documentation for more details on IUnknown methods.
401  */
402 static ULONG WINAPI OLEPictureImpl_AddRef(
403   IPicture* iface)
404 {
405   OLEPictureImpl *This = (OLEPictureImpl *)iface;
406   ULONG refCount = InterlockedIncrement(&This->ref);
407
408   TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
409
410   return refCount;
411 }
412
413 /************************************************************************
414  * OLEPictureImpl_Release (IUnknown)
415  *
416  * See Windows documentation for more details on IUnknown methods.
417  */
418 static ULONG WINAPI OLEPictureImpl_Release(
419       IPicture* iface)
420 {
421   OLEPictureImpl *This = (OLEPictureImpl *)iface;
422   ULONG refCount = InterlockedDecrement(&This->ref);
423
424   TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
425
426   /*
427    * If the reference count goes down to 0, perform suicide.
428    */
429   if (!refCount) OLEPictureImpl_Destroy(This);
430
431   return refCount;
432 }
433
434 /************************************************************************
435  * OLEPictureImpl_QueryInterface (IUnknown)
436  *
437  * See Windows documentation for more details on IUnknown methods.
438  */
439 static HRESULT WINAPI OLEPictureImpl_QueryInterface(
440   IPicture*  iface,
441   REFIID  riid,
442   void**  ppvObject)
443 {
444   OLEPictureImpl *This = (OLEPictureImpl *)iface;
445   TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
446
447   /*
448    * Perform a sanity check on the parameters.
449    */
450   if ( (This==0) || (ppvObject==0) )
451     return E_INVALIDARG;
452
453   /*
454    * Initialize the return parameter.
455    */
456   *ppvObject = 0;
457
458   /*
459    * Compare the riid with the interface IDs implemented by this object.
460    */
461   if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IPicture, riid))
462     *ppvObject = (IPicture*)This;
463   else if (IsEqualIID(&IID_IDispatch, riid))
464     *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
465   else if (IsEqualIID(&IID_IPictureDisp, riid))
466     *ppvObject = (IDispatch*)&(This->lpvtblIDispatch);
467   else if (IsEqualIID(&IID_IPersist, riid) || IsEqualIID(&IID_IPersistStream, riid))
468     *ppvObject = (IPersistStream*)&(This->lpvtblIPersistStream);
469   else if (IsEqualIID(&IID_IConnectionPointContainer, riid))
470     *ppvObject = (IConnectionPointContainer*)&(This->lpvtblIConnectionPointContainer);
471
472   /*
473    * Check that we obtained an interface.
474    */
475   if ((*ppvObject)==0)
476   {
477     FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
478     return E_NOINTERFACE;
479   }
480
481   /*
482    * Query Interface always increases the reference count by one when it is
483    * successful
484    */
485   OLEPictureImpl_AddRef((IPicture*)This);
486
487   return S_OK;
488 }
489
490 /***********************************************************************
491  *    OLEPicture_SendNotify (internal)
492  *
493  * Sends notification messages of changed properties to any interested
494  * connections.
495  */
496 static void OLEPicture_SendNotify(OLEPictureImpl* this, DISPID dispID)
497 {
498   IEnumConnections *pEnum;
499   CONNECTDATA CD;
500
501   if (IConnectionPoint_EnumConnections(this->pCP, &pEnum))
502       return;
503   while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
504     IPropertyNotifySink *sink;
505
506     IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink);
507     IPropertyNotifySink_OnChanged(sink, dispID);
508     IPropertyNotifySink_Release(sink);
509     IUnknown_Release(CD.pUnk);
510   }
511   IEnumConnections_Release(pEnum);
512 }
513
514 /************************************************************************
515  * OLEPictureImpl_get_Handle
516  */
517 static HRESULT WINAPI OLEPictureImpl_get_Handle(IPicture *iface,
518                                                 OLE_HANDLE *phandle)
519 {
520   OLEPictureImpl *This = (OLEPictureImpl *)iface;
521   TRACE("(%p)->(%p)\n", This, phandle);
522   switch(This->desc.picType) {
523   case PICTYPE_NONE:
524   case PICTYPE_UNINITIALIZED:
525     *phandle = 0;
526     break;
527   case PICTYPE_BITMAP:
528     *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
529     break;
530   case PICTYPE_METAFILE:
531     *phandle = (OLE_HANDLE)This->desc.u.wmf.hmeta;
532     break;
533   case PICTYPE_ICON:
534     *phandle = (OLE_HANDLE)This->desc.u.icon.hicon;
535     break;
536   case PICTYPE_ENHMETAFILE:
537     *phandle = (OLE_HANDLE)This->desc.u.emf.hemf;
538     break;
539   default:
540     FIXME("Unimplemented type %d\n", This->desc.picType);
541     return E_NOTIMPL;
542   }
543   TRACE("returning handle %08x\n", *phandle);
544   return S_OK;
545 }
546
547 /************************************************************************
548  * OLEPictureImpl_get_hPal
549  */
550 static HRESULT WINAPI OLEPictureImpl_get_hPal(IPicture *iface,
551                                               OLE_HANDLE *phandle)
552 {
553   OLEPictureImpl *This = (OLEPictureImpl *)iface;
554   HRESULT hres;
555   TRACE("(%p)->(%p)\n", This, phandle);
556
557   if (!phandle)
558     return E_POINTER;
559
560   switch (This->desc.picType) {
561     case (UINT)PICTYPE_UNINITIALIZED:
562     case PICTYPE_NONE:
563       *phandle = 0;
564       hres = S_FALSE;
565       break;
566     case PICTYPE_BITMAP:
567       *phandle = (OLE_HANDLE)This->desc.u.bmp.hpal;
568       hres = S_OK;
569       break;
570     case PICTYPE_METAFILE:
571       hres = E_FAIL;
572       break;
573     case PICTYPE_ICON:
574     case PICTYPE_ENHMETAFILE:
575     default:
576       FIXME("unimplemented for type %d. Returning 0 palette.\n",
577            This->desc.picType);
578       *phandle = 0;
579       hres = S_OK;
580   }
581
582   TRACE("returning 0x%08x, palette handle %08x\n", hres, *phandle);
583   return hres;
584 }
585
586 /************************************************************************
587  * OLEPictureImpl_get_Type
588  */
589 static HRESULT WINAPI OLEPictureImpl_get_Type(IPicture *iface,
590                                               short *ptype)
591 {
592   OLEPictureImpl *This = (OLEPictureImpl *)iface;
593   TRACE("(%p)->(%p): type is %d\n", This, ptype, This->desc.picType);
594   *ptype = This->desc.picType;
595   return S_OK;
596 }
597
598 /************************************************************************
599  * OLEPictureImpl_get_Width
600  */
601 static HRESULT WINAPI OLEPictureImpl_get_Width(IPicture *iface,
602                                                OLE_XSIZE_HIMETRIC *pwidth)
603 {
604   OLEPictureImpl *This = (OLEPictureImpl *)iface;
605   TRACE("(%p)->(%p): width is %d\n", This, pwidth, This->himetricWidth);
606   *pwidth = This->himetricWidth;
607   return S_OK;
608 }
609
610 /************************************************************************
611  * OLEPictureImpl_get_Height
612  */
613 static HRESULT WINAPI OLEPictureImpl_get_Height(IPicture *iface,
614                                                 OLE_YSIZE_HIMETRIC *pheight)
615 {
616   OLEPictureImpl *This = (OLEPictureImpl *)iface;
617   TRACE("(%p)->(%p): height is %d\n", This, pheight, This->himetricHeight);
618   *pheight = This->himetricHeight;
619   return S_OK;
620 }
621
622 /************************************************************************
623  * OLEPictureImpl_Render
624  */
625 static HRESULT WINAPI OLEPictureImpl_Render(IPicture *iface, HDC hdc,
626                                             LONG x, LONG y, LONG cx, LONG cy,
627                                             OLE_XPOS_HIMETRIC xSrc,
628                                             OLE_YPOS_HIMETRIC ySrc,
629                                             OLE_XSIZE_HIMETRIC cxSrc,
630                                             OLE_YSIZE_HIMETRIC cySrc,
631                                             LPCRECT prcWBounds)
632 {
633   OLEPictureImpl *This = (OLEPictureImpl *)iface;
634   TRACE("(%p)->(%p, (%d,%d), (%d,%d) <- (%d,%d), (%d,%d), %p)\n",
635         This, hdc, x, y, cx, cy, xSrc, ySrc, cxSrc, cySrc, prcWBounds);
636   if(prcWBounds)
637     TRACE("prcWBounds (%d,%d) - (%d,%d)\n", prcWBounds->left, prcWBounds->top,
638           prcWBounds->right, prcWBounds->bottom);
639
640   /*
641    * While the documentation suggests this to be here (or after rendering?)
642    * it does cause an endless recursion in my sample app. -MM 20010804
643   OLEPicture_SendNotify(This,DISPID_PICT_RENDER);
644    */
645
646   switch(This->desc.picType) {
647   case PICTYPE_BITMAP:
648     {
649       HBITMAP hbmpOld;
650       HDC hdcBmp;
651
652       /* Set a mapping mode that maps bitmap pixels into HIMETRIC units.
653          NB y-axis gets flipped */
654
655       hdcBmp = CreateCompatibleDC(0);
656       SetMapMode(hdcBmp, MM_ANISOTROPIC);
657       SetWindowOrgEx(hdcBmp, 0, 0, NULL);
658       SetWindowExtEx(hdcBmp, This->himetricWidth, This->himetricHeight, NULL);
659       SetViewportOrgEx(hdcBmp, 0, This->origHeight, NULL);
660       SetViewportExtEx(hdcBmp, This->origWidth, -This->origHeight, NULL);
661
662       if (This->hbmMask) {
663           HDC hdcMask = CreateCompatibleDC(0);
664           HBITMAP hOldbm = SelectObject(hdcMask, This->hbmMask);
665
666           hbmpOld = SelectObject(hdcBmp, This->hbmXor);
667
668           SetMapMode(hdcMask, MM_ANISOTROPIC);
669           SetWindowOrgEx(hdcMask, 0, 0, NULL);
670           SetWindowExtEx(hdcMask, This->himetricWidth, This->himetricHeight, NULL);
671           SetViewportOrgEx(hdcMask, 0, This->origHeight, NULL);
672           SetViewportExtEx(hdcMask, This->origWidth, -This->origHeight, NULL);
673           
674           SetBkColor(hdc, RGB(255, 255, 255));    
675           SetTextColor(hdc, RGB(0, 0, 0));        
676           StretchBlt(hdc, x, y, cx, cy, hdcMask, xSrc, ySrc, cxSrc, cySrc, SRCAND); 
677           StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCPAINT);
678
679           SelectObject(hdcMask, hOldbm);
680           DeleteDC(hdcMask);
681       } else {
682           hbmpOld = SelectObject(hdcBmp, This->desc.u.bmp.hbitmap);
683           StretchBlt(hdc, x, y, cx, cy, hdcBmp, xSrc, ySrc, cxSrc, cySrc, SRCCOPY);
684       }
685
686       SelectObject(hdcBmp, hbmpOld);
687       DeleteDC(hdcBmp);
688     }
689     break;
690   case PICTYPE_ICON:
691     FIXME("Not quite correct implementation of rendering icons...\n");
692     DrawIcon(hdc,x,y,This->desc.u.icon.hicon);
693     break;
694
695   case PICTYPE_METAFILE:
696   {
697     POINT prevOrg;
698     SIZE prevExt;
699     int oldmode;
700
701     oldmode = SetMapMode(hdc, MM_ANISOTROPIC);
702     SetViewportOrgEx(hdc, x, y, &prevOrg);
703     SetViewportExtEx(hdc, cx, cy, &prevExt);
704
705     if (!PlayMetaFile(hdc, This->desc.u.wmf.hmeta))
706         ERR("PlayMetaFile failed!\n");
707
708     SetViewportExtEx(hdc, prevExt.cx, prevExt.cy, NULL);
709     SetViewportOrgEx(hdc, prevOrg.x, prevOrg.y, NULL);
710     SetMapMode(hdc, oldmode);
711     break;
712   }
713
714   case PICTYPE_ENHMETAFILE:
715   {
716     RECT rc = { x, y, x + cx, y + cy };
717     PlayEnhMetaFile(hdc, This->desc.u.emf.hemf, &rc);
718     break;
719   }
720
721   default:
722     FIXME("type %d not implemented\n", This->desc.picType);
723     return E_NOTIMPL;
724   }
725   return S_OK;
726 }
727
728 /************************************************************************
729  * OLEPictureImpl_set_hPal
730  */
731 static HRESULT WINAPI OLEPictureImpl_set_hPal(IPicture *iface,
732                                               OLE_HANDLE hpal)
733 {
734   OLEPictureImpl *This = (OLEPictureImpl *)iface;
735   FIXME("(%p)->(%08x): stub\n", This, hpal);
736   OLEPicture_SendNotify(This,DISPID_PICT_HPAL);
737   return E_NOTIMPL;
738 }
739
740 /************************************************************************
741  * OLEPictureImpl_get_CurDC
742  */
743 static HRESULT WINAPI OLEPictureImpl_get_CurDC(IPicture *iface,
744                                                HDC *phdc)
745 {
746   OLEPictureImpl *This = (OLEPictureImpl *)iface;
747   TRACE("(%p), returning %p\n", This, This->hDCCur);
748   if (phdc) *phdc = This->hDCCur;
749   return S_OK;
750 }
751
752 /************************************************************************
753  * OLEPictureImpl_SelectPicture
754  */
755 static HRESULT WINAPI OLEPictureImpl_SelectPicture(IPicture *iface,
756                                                    HDC hdcIn,
757                                                    HDC *phdcOut,
758                                                    OLE_HANDLE *phbmpOut)
759 {
760   OLEPictureImpl *This = (OLEPictureImpl *)iface;
761   TRACE("(%p)->(%p, %p, %p)\n", This, hdcIn, phdcOut, phbmpOut);
762   if (This->desc.picType == PICTYPE_BITMAP) {
763       SelectObject(hdcIn,This->desc.u.bmp.hbitmap);
764
765       if (phdcOut)
766           *phdcOut = This->hDCCur;
767       This->hDCCur = hdcIn;
768       if (phbmpOut)
769           *phbmpOut = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
770       return S_OK;
771   } else {
772       FIXME("Don't know how to select picture type %d\n",This->desc.picType);
773       return E_FAIL;
774   }
775 }
776
777 /************************************************************************
778  * OLEPictureImpl_get_KeepOriginalFormat
779  */
780 static HRESULT WINAPI OLEPictureImpl_get_KeepOriginalFormat(IPicture *iface,
781                                                             BOOL *pfKeep)
782 {
783   OLEPictureImpl *This = (OLEPictureImpl *)iface;
784   TRACE("(%p)->(%p)\n", This, pfKeep);
785   if (!pfKeep)
786       return E_POINTER;
787   *pfKeep = This->keepOrigFormat;
788   return S_OK;
789 }
790
791 /************************************************************************
792  * OLEPictureImpl_put_KeepOriginalFormat
793  */
794 static HRESULT WINAPI OLEPictureImpl_put_KeepOriginalFormat(IPicture *iface,
795                                                             BOOL keep)
796 {
797   OLEPictureImpl *This = (OLEPictureImpl *)iface;
798   TRACE("(%p)->(%d)\n", This, keep);
799   This->keepOrigFormat = keep;
800   /* FIXME: what DISPID notification here? */
801   return S_OK;
802 }
803
804 /************************************************************************
805  * OLEPictureImpl_PictureChanged
806  */
807 static HRESULT WINAPI OLEPictureImpl_PictureChanged(IPicture *iface)
808 {
809   OLEPictureImpl *This = (OLEPictureImpl *)iface;
810   TRACE("(%p)->()\n", This);
811   OLEPicture_SendNotify(This,DISPID_PICT_HANDLE);
812   This->bIsDirty = TRUE;
813   return S_OK;
814 }
815
816 /************************************************************************
817  * OLEPictureImpl_SaveAsFile
818  */
819 static HRESULT WINAPI OLEPictureImpl_SaveAsFile(IPicture *iface,
820                                                 IStream *pstream,
821                                                 BOOL SaveMemCopy,
822                                                 LONG *pcbSize)
823 {
824   OLEPictureImpl *This = (OLEPictureImpl *)iface;
825   FIXME("(%p)->(%p, %d, %p), hacked stub.\n", This, pstream, SaveMemCopy, pcbSize);
826   return IStream_Write(pstream,This->data,This->datalen,(ULONG*)pcbSize);
827 }
828
829 /************************************************************************
830  * OLEPictureImpl_get_Attributes
831  */
832 static HRESULT WINAPI OLEPictureImpl_get_Attributes(IPicture *iface,
833                                                     DWORD *pdwAttr)
834 {
835   OLEPictureImpl *This = (OLEPictureImpl *)iface;
836   TRACE("(%p)->(%p).\n", This, pdwAttr);
837   *pdwAttr = 0;
838   switch (This->desc.picType) {
839   case PICTYPE_BITMAP:  if (This->hbmMask) *pdwAttr = PICTURE_TRANSPARENT; break;       /* not 'truly' scalable, see MSDN. */
840   case PICTYPE_ICON: *pdwAttr     = PICTURE_TRANSPARENT;break;
841   case PICTYPE_ENHMETAFILE: /* fall through */
842   case PICTYPE_METAFILE: *pdwAttr = PICTURE_TRANSPARENT|PICTURE_SCALABLE;break;
843   default:FIXME("Unknown pictype %d\n",This->desc.picType);break;
844   }
845   return S_OK;
846 }
847
848
849 /************************************************************************
850  *    IConnectionPointContainer
851  */
852 static HRESULT WINAPI OLEPictureImpl_IConnectionPointContainer_QueryInterface(
853   IConnectionPointContainer* iface,
854   REFIID riid,
855   VOID** ppvoid)
856 {
857   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
858
859   return IPicture_QueryInterface((IPicture *)This,riid,ppvoid);
860 }
861
862 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_AddRef(
863   IConnectionPointContainer* iface)
864 {
865   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
866
867   return IPicture_AddRef((IPicture *)This);
868 }
869
870 static ULONG WINAPI OLEPictureImpl_IConnectionPointContainer_Release(
871   IConnectionPointContainer* iface)
872 {
873   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
874
875   return IPicture_Release((IPicture *)This);
876 }
877
878 static HRESULT WINAPI OLEPictureImpl_EnumConnectionPoints(
879   IConnectionPointContainer* iface,
880   IEnumConnectionPoints** ppEnum)
881 {
882   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
883
884   FIXME("(%p,%p), stub!\n",This,ppEnum);
885   return E_NOTIMPL;
886 }
887
888 static HRESULT WINAPI OLEPictureImpl_FindConnectionPoint(
889   IConnectionPointContainer* iface,
890   REFIID riid,
891   IConnectionPoint **ppCP)
892 {
893   OLEPictureImpl *This = impl_from_IConnectionPointContainer(iface);
894   TRACE("(%p,%s,%p)\n",This,debugstr_guid(riid),ppCP);
895   if (!ppCP)
896       return E_POINTER;
897   *ppCP = NULL;
898   if (IsEqualGUID(riid,&IID_IPropertyNotifySink))
899       return IConnectionPoint_QueryInterface(This->pCP,&IID_IConnectionPoint,(LPVOID)ppCP);
900   FIXME("no connection point for %s\n",debugstr_guid(riid));
901   return CONNECT_E_NOCONNECTION;
902 }
903
904
905 /************************************************************************
906  *    IPersistStream
907  */
908
909 /************************************************************************
910  * OLEPictureImpl_IPersistStream_QueryInterface (IUnknown)
911  *
912  * See Windows documentation for more details on IUnknown methods.
913  */
914 static HRESULT WINAPI OLEPictureImpl_IPersistStream_QueryInterface(
915   IPersistStream* iface,
916   REFIID     riid,
917   VOID**     ppvoid)
918 {
919   OLEPictureImpl *This = impl_from_IPersistStream(iface);
920
921   return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
922 }
923
924 /************************************************************************
925  * OLEPictureImpl_IPersistStream_AddRef (IUnknown)
926  *
927  * See Windows documentation for more details on IUnknown methods.
928  */
929 static ULONG WINAPI OLEPictureImpl_IPersistStream_AddRef(
930   IPersistStream* iface)
931 {
932   OLEPictureImpl *This = impl_from_IPersistStream(iface);
933
934   return IPicture_AddRef((IPicture *)This);
935 }
936
937 /************************************************************************
938  * OLEPictureImpl_IPersistStream_Release (IUnknown)
939  *
940  * See Windows documentation for more details on IUnknown methods.
941  */
942 static ULONG WINAPI OLEPictureImpl_IPersistStream_Release(
943   IPersistStream* iface)
944 {
945   OLEPictureImpl *This = impl_from_IPersistStream(iface);
946
947   return IPicture_Release((IPicture *)This);
948 }
949
950 /************************************************************************
951  * OLEPictureImpl_IPersistStream_GetClassID
952  */
953 static HRESULT WINAPI OLEPictureImpl_GetClassID(
954   IPersistStream* iface,CLSID* pClassID)
955 {
956   TRACE("(%p)\n", pClassID);
957   *pClassID = CLSID_StdPicture;
958   return S_OK;
959 }
960
961 /************************************************************************
962  * OLEPictureImpl_IPersistStream_IsDirty
963  */
964 static HRESULT WINAPI OLEPictureImpl_IsDirty(
965   IPersistStream* iface)
966 {
967   OLEPictureImpl *This = impl_from_IPersistStream(iface);
968   FIXME("(%p),stub!\n",This);
969   return E_NOTIMPL;
970 }
971
972 #ifdef SONAME_LIBJPEG
973
974 static void *libjpeg_handle;
975 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
976 MAKE_FUNCPTR(jpeg_std_error);
977 MAKE_FUNCPTR(jpeg_CreateDecompress);
978 MAKE_FUNCPTR(jpeg_read_header);
979 MAKE_FUNCPTR(jpeg_start_decompress);
980 MAKE_FUNCPTR(jpeg_read_scanlines);
981 MAKE_FUNCPTR(jpeg_finish_decompress);
982 MAKE_FUNCPTR(jpeg_destroy_decompress);
983 #undef MAKE_FUNCPTR
984
985 static void *load_libjpeg(void)
986 {
987     if((libjpeg_handle = wine_dlopen(SONAME_LIBJPEG, RTLD_NOW, NULL, 0)) != NULL) {
988
989 #define LOAD_FUNCPTR(f) \
990     if((p##f = wine_dlsym(libjpeg_handle, #f, NULL, 0)) == NULL) { \
991         libjpeg_handle = NULL; \
992         return NULL; \
993     }
994
995         LOAD_FUNCPTR(jpeg_std_error);
996         LOAD_FUNCPTR(jpeg_CreateDecompress);
997         LOAD_FUNCPTR(jpeg_read_header);
998         LOAD_FUNCPTR(jpeg_start_decompress);
999         LOAD_FUNCPTR(jpeg_read_scanlines);
1000         LOAD_FUNCPTR(jpeg_finish_decompress);
1001         LOAD_FUNCPTR(jpeg_destroy_decompress);
1002 #undef LOAD_FUNCPTR
1003     }
1004     return libjpeg_handle;
1005 }
1006
1007 /* for the jpeg decompressor source manager. */
1008 static void _jpeg_init_source(j_decompress_ptr cinfo) { }
1009
1010 static jpeg_boolean _jpeg_fill_input_buffer(j_decompress_ptr cinfo) {
1011     ERR("(), should not get here.\n");
1012     return FALSE;
1013 }
1014
1015 static void _jpeg_skip_input_data(j_decompress_ptr cinfo,long num_bytes) {
1016     TRACE("Skipping %ld bytes...\n", num_bytes);
1017     cinfo->src->next_input_byte += num_bytes;
1018     cinfo->src->bytes_in_buffer -= num_bytes;
1019 }
1020
1021 static jpeg_boolean _jpeg_resync_to_restart(j_decompress_ptr cinfo, int desired) {
1022     ERR("(desired=%d), should not get here.\n",desired);
1023     return FALSE;
1024 }
1025 static void _jpeg_term_source(j_decompress_ptr cinfo) { }
1026 #endif /* SONAME_LIBJPEG */
1027
1028 struct gifdata {
1029     unsigned char *data;
1030     unsigned int curoff;
1031     unsigned int len;
1032 };
1033
1034 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1035     struct gifdata *gd = (struct gifdata*)gif->UserData;
1036
1037     if (len+gd->curoff > gd->len) {
1038         ERR("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff);
1039         len = gd->len - gd->curoff;
1040     }
1041     memcpy(data, gd->data+gd->curoff, len);
1042     gd->curoff += len;
1043     return len;
1044 }
1045
1046
1047 static HRESULT OLEPictureImpl_LoadGif(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1048 {
1049     struct gifdata      gd;
1050     GifFileType         *gif;
1051     BITMAPINFO          *bmi;
1052     HDC                 hdcref;
1053     LPBYTE              bytes;
1054     int                 i,j,ret;
1055     GifImageDesc        *gid;
1056     SavedImage          *si;
1057     ColorMapObject      *cm;
1058     int                 transparent = -1;
1059     ExtensionBlock      *eb;
1060     int                 padding;
1061
1062     gd.data   = xbuf;
1063     gd.curoff = 0;
1064     gd.len    = xread;
1065     gif = DGifOpen((void*)&gd, _gif_inputfunc);
1066     ret = DGifSlurp(gif);
1067     if (ret == GIF_ERROR) {
1068       ERR("Failed reading GIF using libgif.\n");
1069       return E_FAIL;
1070     }
1071     TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight);
1072     TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor);
1073     TRACE("imgcnt %d\n", gif->ImageCount);
1074     if (gif->ImageCount<1) {
1075       ERR("GIF stream does not have images inside?\n");
1076       return E_FAIL;
1077     }
1078     TRACE("curimage: %d x %d, on %dx%d, interlace %d\n",
1079       gif->Image.Width, gif->Image.Height,
1080       gif->Image.Left, gif->Image.Top,
1081       gif->Image.Interlace
1082     );
1083     /* */
1084     padding = (gif->SWidth+3) & ~3;
1085     si   = gif->SavedImages+0;
1086     gid  = &(si->ImageDesc);
1087     cm   = gid->ColorMap;
1088     if (!cm) cm = gif->SColorMap;
1089     bmi  = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(cm->ColorCount)*sizeof(RGBQUAD));
1090     bytes= HeapAlloc(GetProcessHeap(),0,padding*gif->SHeight);
1091     
1092     /* look for the transparent color extension */
1093     for (i = 0; i < si->ExtensionBlockCount; ++i) {
1094         eb = si->ExtensionBlocks + i;
1095         if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1096             if ((eb->Bytes[0] & 1) == 1) {
1097                 transparent = (unsigned char)eb->Bytes[3];
1098             }
1099         }
1100     }
1101
1102     for (i = 0; i < cm->ColorCount; i++) {
1103       bmi->bmiColors[i].rgbRed = cm->Colors[i].Red;
1104       bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green;
1105       bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue;
1106       if (i == transparent) {
1107           This->rgbTrans = RGB(bmi->bmiColors[i].rgbRed,
1108                                bmi->bmiColors[i].rgbGreen,
1109                                bmi->bmiColors[i].rgbBlue);
1110       }
1111     }
1112
1113     /* Map to in picture coordinates */
1114     for (i = 0, j = 0; i < gid->Height; i++) {
1115         if (gif->Image.Interlace) {
1116             memcpy(
1117                 bytes + (gid->Top + j) * padding + gid->Left,
1118                 si->RasterBits + i * gid->Width,
1119                 gid->Width);
1120
1121             /* Lower bits of interlaced counter encode current interlace */
1122             if (j & 1) j += 2;      /* Currently filling odd rows */
1123             else if (j & 2) j += 4; /* Currently filling even rows not multiples of 4 */
1124             else j += 8;            /* Currently filling every 8th row or 4th row in-between */
1125
1126             if (j >= gid->Height && i < gid->Height && (j & 1) == 0) {
1127                 /* End of current interlace, go to next interlace */
1128                 if (j & 2) j = 1;       /* Next iteration fills odd rows */
1129                 else if (j & 4) j = 2;  /* Next iteration fills even rows not mod 4 and not mod 8 */
1130                 else j = 4;             /* Next iteration fills rows in-between rows mod 6 */
1131             }
1132         } else {
1133             memcpy(
1134                 bytes + (gid->Top + i) * padding + gid->Left,
1135                 si->RasterBits + i * gid->Width,
1136                 gid->Width);
1137         }
1138     }
1139
1140     bmi->bmiHeader.biSize               = sizeof(BITMAPINFOHEADER);
1141     bmi->bmiHeader.biWidth              = gif->SWidth;
1142     bmi->bmiHeader.biHeight             = -gif->SHeight;
1143     bmi->bmiHeader.biPlanes             = 1;
1144     bmi->bmiHeader.biBitCount           = 8;
1145     bmi->bmiHeader.biCompression        = BI_RGB;
1146     bmi->bmiHeader.biSizeImage          = padding*gif->SHeight;
1147     bmi->bmiHeader.biXPelsPerMeter      = 0;
1148     bmi->bmiHeader.biYPelsPerMeter      = 0;
1149     bmi->bmiHeader.biClrUsed            = cm->ColorCount;
1150     bmi->bmiHeader.biClrImportant       = 0;
1151
1152     hdcref = GetDC(0);
1153     This->desc.u.bmp.hbitmap=CreateDIBitmap(
1154             hdcref,
1155             &bmi->bmiHeader,
1156             CBM_INIT,
1157             bytes,
1158             bmi,
1159             DIB_RGB_COLORS
1160     );
1161
1162     if (transparent > -1) {
1163         /* Create the Mask */
1164         HDC hdc = CreateCompatibleDC(0);
1165         HDC hdcMask = CreateCompatibleDC(0);
1166         HBITMAP hOldbitmap; 
1167         HBITMAP hOldbitmapmask;
1168
1169         unsigned int monopadding = (((unsigned)(gif->SWidth + 31)) >> 5) << 2;
1170         HBITMAP hTempMask;
1171
1172         This->hbmXor = CreateDIBitmap(
1173             hdcref,
1174             &bmi->bmiHeader,
1175             CBM_INIT,
1176             bytes,
1177             bmi,
1178             DIB_RGB_COLORS
1179         );
1180
1181         bmi->bmiColors[0].rgbRed = 0;
1182         bmi->bmiColors[0].rgbGreen = 0;
1183         bmi->bmiColors[0].rgbBlue = 0;
1184         bmi->bmiColors[1].rgbRed = 255;
1185         bmi->bmiColors[1].rgbGreen = 255;
1186         bmi->bmiColors[1].rgbBlue = 255;
1187
1188         bmi->bmiHeader.biBitCount               = 1;
1189         bmi->bmiHeader.biSizeImage              = monopadding*gif->SHeight;
1190         bmi->bmiHeader.biClrUsed                = 2;
1191
1192         for (i = 0; i < gif->SHeight; i++) {
1193             unsigned char * colorPointer = bytes + padding * i;
1194             unsigned char * monoPointer = bytes + monopadding * i;
1195             for (j = 0; j < gif->SWidth; j++) {
1196                 unsigned char pixel = colorPointer[j];
1197                 if ((j & 7) == 0) monoPointer[j >> 3] = 0;
1198                 if (pixel == (transparent & 0x000000FFU)) monoPointer[j >> 3] |= 1 << (7 - (j & 7));
1199             }
1200         }
1201         hdcref = GetDC(0);
1202         hTempMask = CreateDIBitmap(
1203                 hdcref,
1204                 &bmi->bmiHeader,
1205                 CBM_INIT,
1206                 bytes,
1207                 bmi,
1208                 DIB_RGB_COLORS
1209         );
1210         DeleteDC(hdcref);
1211
1212         bmi->bmiHeader.biHeight = -bmi->bmiHeader.biHeight;
1213         This->hbmMask = CreateBitmap(bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 1, 1, NULL);
1214         hOldbitmap = SelectObject(hdc, hTempMask);
1215         hOldbitmapmask = SelectObject(hdcMask, This->hbmMask);
1216
1217         SetBkColor(hdc, RGB(255, 255, 255));
1218         BitBlt(hdcMask, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, hdc, 0, 0, SRCCOPY);
1219
1220         /* We no longer need the original bitmap, so we apply the first
1221            transformation with the mask to speed up the rendering */
1222         SelectObject(hdc, This->hbmXor);
1223         SetBkColor(hdc, RGB(0,0,0));
1224         SetTextColor(hdc, RGB(255,255,255));
1225         BitBlt(hdc, 0, 0, bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight, 
1226                  hdcMask, 0, 0,  SRCAND);
1227
1228         SelectObject(hdc, hOldbitmap);
1229         SelectObject(hdcMask, hOldbitmapmask);
1230         DeleteDC(hdcMask);
1231         DeleteDC(hdc);
1232         DeleteObject(hTempMask);
1233     }
1234     
1235     DeleteDC(hdcref);
1236     This->desc.picType = PICTYPE_BITMAP;
1237     OLEPictureImpl_SetBitmap(This);
1238     DGifCloseFile(gif);
1239     HeapFree(GetProcessHeap(),0,bmi);
1240     HeapFree(GetProcessHeap(),0,bytes);
1241     return S_OK;
1242 }
1243
1244 static HRESULT OLEPictureImpl_LoadJpeg(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1245 {
1246 #ifdef SONAME_LIBJPEG
1247     struct jpeg_decompress_struct       jd;
1248     struct jpeg_error_mgr               jerr;
1249     int                                 ret;
1250     JDIMENSION                          x;
1251     JSAMPROW                            samprow,oldsamprow;
1252     BITMAPINFOHEADER                    bmi;
1253     LPBYTE                              bits;
1254     HDC                                 hdcref;
1255     struct jpeg_source_mgr              xjsm;
1256     LPBYTE                              oldbits;
1257     unsigned int i;
1258
1259     if(!libjpeg_handle) {
1260         if(!load_libjpeg()) {
1261             ERR("Failed reading JPEG because unable to find %s\n", SONAME_LIBJPEG);
1262             return E_FAIL;
1263         }
1264     }
1265
1266     /* This is basically so we can use in-memory data for jpeg decompression.
1267      * We need to have all the functions.
1268      */
1269     xjsm.next_input_byte        = xbuf;
1270     xjsm.bytes_in_buffer        = xread;
1271     xjsm.init_source            = _jpeg_init_source;
1272     xjsm.fill_input_buffer      = _jpeg_fill_input_buffer;
1273     xjsm.skip_input_data        = _jpeg_skip_input_data;
1274     xjsm.resync_to_restart      = _jpeg_resync_to_restart;
1275     xjsm.term_source            = _jpeg_term_source;
1276
1277     jd.err = pjpeg_std_error(&jerr);
1278     /* jpeg_create_decompress is a macro that expands to jpeg_CreateDecompress - see jpeglib.h
1279      * jpeg_create_decompress(&jd); */
1280     pjpeg_CreateDecompress(&jd, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
1281     jd.src = &xjsm;
1282     ret=pjpeg_read_header(&jd,TRUE);
1283     jd.out_color_space = JCS_RGB;
1284     pjpeg_start_decompress(&jd);
1285     if (ret != JPEG_HEADER_OK) {
1286         ERR("Jpeg image in stream has bad format, read header returned %d.\n",ret);
1287         HeapFree(GetProcessHeap(),0,xbuf);
1288         return E_FAIL;
1289     }
1290
1291     bits = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
1292                      (jd.output_height+1) * ((jd.output_width*jd.output_components + 3) & ~3) );
1293     samprow=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,jd.output_width*jd.output_components);
1294
1295     oldbits = bits;
1296     oldsamprow = samprow;
1297     while ( jd.output_scanline<jd.output_height ) {
1298       x = pjpeg_read_scanlines(&jd,&samprow,1);
1299       if (x != 1) {
1300         ERR("failed to read current scanline?\n");
1301         break;
1302       }
1303       /* We have to convert from RGB to BGR, see MSDN/ BITMAPINFOHEADER */
1304       for(i=0;i<jd.output_width;i++,samprow+=jd.output_components) {
1305         *(bits++) = *(samprow+2);
1306         *(bits++) = *(samprow+1);
1307         *(bits++) = *(samprow);
1308       }
1309       bits = (LPBYTE)(((UINT_PTR)bits + 3) & ~3);
1310       samprow = oldsamprow;
1311     }
1312     bits = oldbits;
1313
1314     bmi.biSize          = sizeof(bmi);
1315     bmi.biWidth         =  jd.output_width;
1316     bmi.biHeight        = -jd.output_height;
1317     bmi.biPlanes        = 1;
1318     bmi.biBitCount      = jd.output_components<<3;
1319     bmi.biCompression   = BI_RGB;
1320     bmi.biSizeImage     = jd.output_height*jd.output_width*jd.output_components;
1321     bmi.biXPelsPerMeter = 0;
1322     bmi.biYPelsPerMeter = 0;
1323     bmi.biClrUsed       = 0;
1324     bmi.biClrImportant  = 0;
1325
1326     HeapFree(GetProcessHeap(),0,samprow);
1327     pjpeg_finish_decompress(&jd);
1328     pjpeg_destroy_decompress(&jd);
1329     hdcref = GetDC(0);
1330     This->desc.u.bmp.hbitmap=CreateDIBitmap(
1331             hdcref,
1332             &bmi,
1333             CBM_INIT,
1334             bits,
1335             (BITMAPINFO*)&bmi,
1336             DIB_RGB_COLORS
1337     );
1338     DeleteDC(hdcref);
1339     This->desc.picType = PICTYPE_BITMAP;
1340     OLEPictureImpl_SetBitmap(This);
1341     HeapFree(GetProcessHeap(),0,bits);
1342     return S_OK;
1343 #else
1344     ERR("Trying to load JPEG picture, but JPEG supported not compiled in.\n");
1345     return E_FAIL;
1346 #endif
1347 }
1348
1349 static HRESULT OLEPictureImpl_LoadDIB(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1350 {
1351     BITMAPFILEHEADER    *bfh = (BITMAPFILEHEADER*)xbuf;
1352     BITMAPINFO          *bi = (BITMAPINFO*)(bfh+1);
1353     HDC                 hdcref;
1354
1355     /* Does not matter whether this is a coreheader or not, we only use
1356      * components which are in both
1357      */
1358     hdcref = GetDC(0);
1359     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1360         hdcref,
1361         &(bi->bmiHeader),
1362         CBM_INIT,
1363         xbuf+bfh->bfOffBits,
1364         bi,
1365        DIB_RGB_COLORS
1366     );
1367     DeleteDC(hdcref);
1368     if (This->desc.u.bmp.hbitmap == 0)
1369         return E_FAIL;
1370     This->desc.picType = PICTYPE_BITMAP;
1371     OLEPictureImpl_SetBitmap(This);
1372     return S_OK;
1373 }
1374
1375 /*****************************************************
1376 *   start of PNG-specific code
1377 *   currently only supports colortype PNG_COLOR_TYPE_RGB
1378 */
1379 #ifdef SONAME_LIBPNG
1380 typedef struct{
1381     ULONG position;
1382     ULONG size;
1383     BYTE * buff;
1384 } png_io;
1385
1386 static void png_stream_read_data(png_structp png_ptr, png_bytep data,
1387     png_size_t length)
1388 {
1389     png_io * io_ptr = png_ptr->io_ptr;
1390
1391     if(length + io_ptr->position > io_ptr->size){
1392         length = io_ptr->size - io_ptr->position;
1393     }
1394
1395     memcpy(data, io_ptr->buff + io_ptr->position, length);
1396
1397     io_ptr->position += length;
1398 }
1399
1400 static void *libpng_handle;
1401 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
1402 MAKE_FUNCPTR(png_create_read_struct);
1403 MAKE_FUNCPTR(png_create_info_struct);
1404 MAKE_FUNCPTR(png_set_read_fn);
1405 MAKE_FUNCPTR(png_read_info);
1406 MAKE_FUNCPTR(png_read_image);
1407 MAKE_FUNCPTR(png_get_rowbytes);
1408 MAKE_FUNCPTR(png_set_bgr);
1409 MAKE_FUNCPTR(png_destroy_read_struct);
1410 MAKE_FUNCPTR(png_set_palette_to_rgb);
1411 MAKE_FUNCPTR(png_read_update_info);
1412 MAKE_FUNCPTR(png_get_tRNS);
1413 MAKE_FUNCPTR(png_get_PLTE);
1414 MAKE_FUNCPTR(png_set_expand);
1415 #undef MAKE_FUNCPTR
1416
1417 static void *load_libpng(void)
1418 {
1419     if((libpng_handle = wine_dlopen(SONAME_LIBPNG, RTLD_NOW, NULL, 0)) != NULL) {
1420
1421 #define LOAD_FUNCPTR(f) \
1422     if((p##f = wine_dlsym(libpng_handle, #f, NULL, 0)) == NULL) { \
1423         libpng_handle = NULL; \
1424         return NULL; \
1425     }
1426         LOAD_FUNCPTR(png_create_read_struct);
1427         LOAD_FUNCPTR(png_create_info_struct);
1428         LOAD_FUNCPTR(png_set_read_fn);
1429         LOAD_FUNCPTR(png_read_info);
1430         LOAD_FUNCPTR(png_read_image);
1431         LOAD_FUNCPTR(png_get_rowbytes);
1432         LOAD_FUNCPTR(png_set_bgr);
1433         LOAD_FUNCPTR(png_destroy_read_struct);
1434         LOAD_FUNCPTR(png_set_palette_to_rgb);
1435         LOAD_FUNCPTR(png_read_update_info);
1436         LOAD_FUNCPTR(png_get_tRNS);
1437         LOAD_FUNCPTR(png_get_PLTE);
1438         LOAD_FUNCPTR(png_set_expand);
1439
1440 #undef LOAD_FUNCPTR
1441     }
1442     return libpng_handle;
1443 }
1444 #endif /* SONAME_LIBPNG */
1445
1446 static HRESULT OLEPictureImpl_LoadPNG(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1447 {
1448 #ifdef SONAME_LIBPNG
1449     png_io              io;
1450     png_structp         png_ptr = NULL;
1451     png_infop           info_ptr = NULL;
1452     INT                 row, rowsize, height, width, num_trans, i, j;
1453     png_bytep*          row_pointers = NULL;
1454     png_bytep           pngdata = NULL;
1455     BITMAPINFOHEADER    bmi;
1456     HDC                 hdcref = NULL, hdcXor, hdcMask;
1457     HRESULT             ret;
1458     BOOL                transparency;
1459     png_bytep           trans;
1460     png_color_16p       trans_values;
1461     COLORREF            white = RGB(255, 255, 255), black = RGB(0, 0, 0);
1462     HBITMAP             hbmoldXor, hbmoldMask, temp;
1463
1464     if(!libpng_handle) {
1465         if(!load_libpng()) {
1466             ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
1467             return E_FAIL;
1468         }
1469     }
1470
1471     io.size     = xread;
1472     io.position = 0;
1473     io.buff     = xbuf;
1474
1475     png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING,
1476         NULL, NULL, NULL);
1477
1478     if(setjmp(png_jmpbuf(png_ptr))){
1479         TRACE("Error in libpng\n");
1480         ret = E_FAIL;
1481         goto end;
1482     }
1483
1484     info_ptr = ppng_create_info_struct(png_ptr);
1485     ppng_set_read_fn(png_ptr, &io, png_stream_read_data);
1486     ppng_read_info(png_ptr, info_ptr);
1487
1488     if(!(png_ptr->color_type == PNG_COLOR_TYPE_RGB ||
1489          png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
1490          png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)){
1491         FIXME("Unsupported .PNG type: %d\n", png_ptr->color_type);
1492         ret = E_FAIL;
1493         goto end;
1494     }
1495
1496     transparency = (ppng_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values)
1497                        == PNG_INFO_tRNS);
1498
1499     /* sets format from anything to RGBA */
1500     ppng_set_expand(png_ptr);
1501     /* sets format to BGRA */
1502     ppng_set_bgr(png_ptr);
1503
1504     ppng_read_update_info(png_ptr, info_ptr);
1505
1506     rowsize = ppng_get_rowbytes(png_ptr, info_ptr);
1507     /* align rowsize to 4-byte boundary */
1508     rowsize = (rowsize + 3) & ~3;
1509     height = info_ptr->height;
1510     width = info_ptr->width;
1511
1512     pngdata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, height * rowsize);
1513     row_pointers = HeapAlloc(GetProcessHeap(), 0, height * (sizeof(VOID *)));
1514
1515     if(!pngdata || !row_pointers){
1516         ret = E_FAIL;
1517         goto end;
1518     }
1519
1520     for (row = 0; row < height; row++){
1521         row_pointers[row] = pngdata + row * rowsize;
1522     }
1523
1524     ppng_read_image(png_ptr, row_pointers);
1525
1526     bmi.biSize          = sizeof(bmi);
1527     bmi.biWidth         = width;
1528     bmi.biHeight        = -height;
1529     bmi.biPlanes        = 1;
1530     bmi.biBitCount      = info_ptr->channels * 8;
1531     bmi.biCompression   = BI_RGB;
1532     bmi.biSizeImage     = height * rowsize;
1533     bmi.biXPelsPerMeter = 0;
1534     bmi.biYPelsPerMeter = 0;
1535     bmi.biClrUsed       = 0;
1536     bmi.biClrImportant  = 0;
1537
1538     hdcref = GetDC(0);
1539     This->desc.u.bmp.hbitmap = CreateDIBitmap(
1540         hdcref,
1541         &bmi,
1542         CBM_INIT,
1543         pngdata,
1544         (BITMAPINFO*)&bmi,
1545         DIB_RGB_COLORS
1546     );
1547
1548     /* only fully-transparent alpha is handled */
1549     if((info_ptr->channels != 4) || !transparency){
1550         ReleaseDC(0, hdcref);
1551         goto succ;
1552     }
1553
1554     This->hbmXor = CreateDIBitmap(
1555         hdcref,
1556         &bmi,
1557         CBM_INIT,
1558         pngdata,
1559         (BITMAPINFO*)&bmi,
1560         DIB_RGB_COLORS
1561     );
1562
1563     /* set transparent pixels to black, all others to white */
1564     for(i = 0; i < height; i++){
1565         for(j = 3; j < rowsize; j += 4){
1566             if(row_pointers[i][j] == 0)
1567                 *((DWORD*)(&row_pointers[i][j - 3])) = black;
1568             else
1569                 *((DWORD*)(&row_pointers[i][j - 3])) = white;
1570         }
1571     }
1572
1573     temp = CreateDIBitmap(
1574         hdcref,
1575         &bmi,
1576         CBM_INIT,
1577         pngdata,
1578         (BITMAPINFO*)&bmi,
1579         DIB_RGB_COLORS
1580     );
1581
1582     ReleaseDC(0, hdcref);
1583
1584     This->hbmMask = CreateBitmap(width,-height,1,1,NULL);
1585     hdcXor = CreateCompatibleDC(NULL);
1586     hdcMask = CreateCompatibleDC(NULL);
1587
1588     hbmoldXor = SelectObject(hdcXor,temp);
1589     hbmoldMask = SelectObject(hdcMask,This->hbmMask);
1590     SetBkColor(hdcXor,black);
1591     BitBlt(hdcMask,0,0,width,height,hdcXor,0,0,SRCCOPY);
1592
1593     SelectObject(hdcXor,This->hbmXor);
1594     DeleteObject(temp);
1595
1596     SetTextColor(hdcXor,white);
1597     SetBkColor(hdcXor,black);
1598     BitBlt(hdcXor,0,0,width,height,hdcMask,0,0,SRCAND);
1599
1600     SelectObject(hdcXor,hbmoldXor);
1601     SelectObject(hdcMask,hbmoldMask);
1602
1603     DeleteDC(hdcXor);
1604     DeleteDC(hdcMask);
1605
1606 succ:
1607     This->desc.picType = PICTYPE_BITMAP;
1608     OLEPictureImpl_SetBitmap(This);
1609     ret = S_OK;
1610
1611 end:
1612     if(png_ptr)
1613         ppng_destroy_read_struct(&png_ptr,
1614                                 (info_ptr ? &info_ptr : (png_infopp) NULL),
1615                                 (png_infopp)NULL);
1616     HeapFree(GetProcessHeap(), 0, row_pointers);
1617     HeapFree(GetProcessHeap(), 0, pngdata);
1618     return ret;
1619 #else /* SONAME_LIBPNG */
1620     ERR("Trying to load PNG picture, but PNG supported not compiled in.\n");
1621     return E_FAIL;
1622 #endif
1623 }
1624
1625 /*****************************************************
1626 *   start of Icon-specific code
1627 */
1628
1629 static HRESULT OLEPictureImpl_LoadIcon(OLEPictureImpl *This, BYTE *xbuf, ULONG xread)
1630 {
1631     HICON hicon;
1632     CURSORICONFILEDIR   *cifd = (CURSORICONFILEDIR*)xbuf;
1633     HDC hdcRef;
1634     int i;
1635
1636     /*
1637     FIXME("icon.idReserved=%d\n",cifd->idReserved);
1638     FIXME("icon.idType=%d\n",cifd->idType);
1639     FIXME("icon.idCount=%d\n",cifd->idCount);
1640
1641     for (i=0;i<cifd->idCount;i++) {
1642         FIXME("[%d] width %d\n",i,cifd->idEntries[i].bWidth);
1643         FIXME("[%d] height %d\n",i,cifd->idEntries[i].bHeight);
1644         FIXME("[%d] bColorCount %d\n",i,cifd->idEntries[i].bColorCount);
1645         FIXME("[%d] bReserved %d\n",i,cifd->idEntries[i].bReserved);
1646         FIXME("[%d] xHotspot %d\n",i,cifd->idEntries[i].xHotspot);
1647         FIXME("[%d] yHotspot %d\n",i,cifd->idEntries[i].yHotspot);
1648         FIXME("[%d] dwDIBSize %d\n",i,cifd->idEntries[i].dwDIBSize);
1649         FIXME("[%d] dwDIBOffset %d\n",i,cifd->idEntries[i].dwDIBOffset);
1650     }
1651     */
1652     i=0;
1653     /* If we have more than one icon, try to find the best.
1654      * this currently means '32 pixel wide'.
1655      */
1656     if (cifd->idCount!=1) {
1657         for (i=0;i<cifd->idCount;i++) {
1658             if (cifd->idEntries[i].bWidth == 32)
1659                 break;
1660         }
1661         if (i==cifd->idCount) i=0;
1662     }
1663
1664     hicon = CreateIconFromResourceEx(
1665                 xbuf+cifd->idEntries[i].dwDIBOffset,
1666                 cifd->idEntries[i].dwDIBSize,
1667                 TRUE, /* is icon */
1668                 0x00030000,
1669                 cifd->idEntries[i].bWidth,
1670                 cifd->idEntries[i].bHeight,
1671                 0
1672     );
1673     if (!hicon) {
1674         ERR("CreateIcon failed.\n");
1675         return E_FAIL;
1676     } else {
1677         This->desc.picType = PICTYPE_ICON;
1678         This->desc.u.icon.hicon = hicon;
1679         This->origWidth = cifd->idEntries[i].bWidth;
1680         This->origHeight = cifd->idEntries[i].bHeight;
1681         hdcRef = CreateCompatibleDC(0);
1682         This->himetricWidth =(cifd->idEntries[i].bWidth *2540)/GetDeviceCaps(hdcRef, LOGPIXELSX);
1683         This->himetricHeight=(cifd->idEntries[i].bHeight*2540)/GetDeviceCaps(hdcRef, LOGPIXELSY);
1684         DeleteDC(hdcRef);
1685         return S_OK;
1686     }
1687 }
1688
1689 static HRESULT OLEPictureImpl_LoadEnhMetafile(OLEPictureImpl *This,
1690                                               const BYTE *data, ULONG size)
1691 {
1692     HENHMETAFILE hemf;
1693     ENHMETAHEADER hdr;
1694
1695     hemf = SetEnhMetaFileBits(size, data);
1696     if (!hemf) return E_FAIL;
1697
1698     GetEnhMetaFileHeader(hemf, sizeof(hdr), &hdr);
1699
1700     This->desc.picType = PICTYPE_ENHMETAFILE;
1701     This->desc.u.emf.hemf = hemf;
1702
1703     This->origWidth = 0;
1704     This->origHeight = 0;
1705     This->himetricWidth = hdr.rclFrame.right - hdr.rclFrame.left;
1706     This->himetricHeight = hdr.rclFrame.bottom - hdr.rclFrame.top;
1707
1708     return S_OK;
1709 }
1710
1711 static HRESULT OLEPictureImpl_LoadAPM(OLEPictureImpl *This,
1712                                       const BYTE *data, ULONG size)
1713 {
1714     APM_HEADER *header = (APM_HEADER *)data;
1715     HMETAFILE hmf;
1716
1717     if (size < sizeof(APM_HEADER))
1718         return E_FAIL;
1719     if (header->key != 0x9ac6cdd7)
1720         return E_FAIL;
1721
1722     /* SetMetaFileBitsEx performs data check on its own */
1723     hmf = SetMetaFileBitsEx(size - sizeof(*header), data + sizeof(*header));
1724     if (!hmf) return E_FAIL;
1725
1726     This->desc.picType = PICTYPE_METAFILE;
1727     This->desc.u.wmf.hmeta = hmf;
1728     This->desc.u.wmf.xExt = 0;
1729     This->desc.u.wmf.yExt = 0;
1730
1731     This->origWidth = 0;
1732     This->origHeight = 0;
1733     This->himetricWidth = MulDiv((INT)header->right - header->left, 2540, header->inch);
1734     This->himetricHeight = MulDiv((INT)header->bottom - header->top, 2540, header->inch);
1735     return S_OK;
1736 }
1737
1738 /************************************************************************
1739  * BITMAP FORMAT FLAGS -
1740  *   Flags that differentiate between different types of bitmaps.
1741  */
1742
1743 #define BITMAP_FORMAT_BMP   0x4d42 /* "BM" */
1744 #define BITMAP_FORMAT_JPEG  0xd8ff
1745 #define BITMAP_FORMAT_GIF   0x4947
1746 #define BITMAP_FORMAT_PNG   0x5089
1747 #define BITMAP_FORMAT_APM   0xcdd7
1748
1749 /************************************************************************
1750  * OLEPictureImpl_IPersistStream_Load (IUnknown)
1751  *
1752  * Loads the binary data from the IStream. Starts at current position.
1753  * There appears to be an 2 DWORD header:
1754  *      DWORD magic;
1755  *      DWORD len;
1756  *
1757  * Currently implemented: BITMAP, ICON, JPEG, GIF, WMF, EMF
1758  */
1759 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
1760   HRESULT       hr = E_FAIL;
1761   BOOL          headerisdata = FALSE;
1762   BOOL          statfailed = FALSE;
1763   ULONG         xread, toread;
1764   ULONG         headerread;
1765   BYTE          *xbuf;
1766   DWORD         header[2];
1767   WORD          magic;
1768   STATSTG       statstg;
1769   OLEPictureImpl *This = impl_from_IPersistStream(iface);
1770   
1771   TRACE("(%p,%p)\n",This,pStm);
1772
1773   /****************************************************************************************
1774    * Part 1: Load the data
1775    */
1776   /* Sometimes we have a header, sometimes we don't. Apply some guesses to find
1777    * out whether we do.
1778    *
1779    * UPDATE: the IStream can be mapped to a plain file instead of a stream in a
1780    * compound file. This may explain most, if not all, of the cases of "no
1781    * header", and the header validation should take this into account.
1782    * At least in Visual Basic 6, resource streams, valid headers are
1783    *    header[0] == "lt\0\0",
1784    *    header[1] == length_of_stream.
1785    *
1786    * Also handle streams where we do not have a working "Stat" method by
1787    * reading all data until the end of the stream.
1788    */
1789   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
1790   if (hr) {
1791       TRACE("stat failed with hres %x, proceeding to read all data.\n",hr);
1792       statfailed = TRUE;
1793       /* we will read at least 8 byte ... just right below */
1794       statstg.cbSize.QuadPart = 8;
1795   }
1796
1797   toread = 0;
1798   headerread = 0;
1799   headerisdata = FALSE;
1800   do {
1801       hr=IStream_Read(pStm,header,8,&xread);
1802       if (hr || xread!=8) {
1803           ERR("Failure while reading picture header (hr is %x, nread is %d).\n",hr,xread);
1804           return (hr?hr:E_FAIL);
1805       }
1806       headerread += xread;
1807       xread = 0;
1808       
1809       if (!memcmp(&(header[0]),"lt\0\0", 4) && (statfailed || (header[1] + headerread <= statstg.cbSize.QuadPart))) {
1810           if (toread != 0 && toread != header[1]) 
1811               FIXME("varying lengths of image data (prev=%u curr=%u), only last one will be used\n",
1812                   toread, header[1]);
1813           toread = header[1];
1814           if (toread == 0) break;
1815       } else {
1816           if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
1817               !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
1818               !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
1819               (header[0] == EMR_HEADER)            ||   /* EMF header */
1820               (header[1] > statstg.cbSize.QuadPart)||   /* invalid size */
1821               (header[1]==0)
1822           ) {/* Found start of bitmap data */
1823               headerisdata = TRUE;
1824               if (toread == 0) 
1825                   toread = statstg.cbSize.QuadPart-8;
1826               else toread -= 8;
1827               xread = 8;
1828           } else {
1829               FIXME("Unknown stream header magic: %08x\n", header[0]);
1830               toread = header[1];
1831           }
1832       }
1833   } while (!headerisdata);
1834
1835   if (statfailed) { /* we don't know the size ... read all we get */
1836       int sizeinc = 4096;
1837       int origsize = sizeinc;
1838       ULONG nread = 42;
1839
1840       TRACE("Reading all data from stream.\n");
1841       xbuf = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, origsize);
1842       if (headerisdata)
1843           memcpy (xbuf, header, 8);
1844       while (1) {
1845           while (xread < origsize) {
1846               hr = IStream_Read(pStm,xbuf+xread,origsize-xread,&nread);
1847               xread+=nread;
1848               if (hr || !nread)
1849                   break;
1850           }
1851           if (!nread || hr) /* done, or error */
1852               break;
1853           if (xread == origsize) {
1854               origsize += sizeinc;
1855               sizeinc = 2*sizeinc; /* exponential increase */
1856               xbuf = HeapReAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, xbuf, origsize);
1857           }
1858       }
1859       if (hr)
1860           TRACE("hr in no-stat loader case is %08x\n", hr);
1861       TRACE("loaded %d bytes.\n", xread);
1862       This->datalen = xread;
1863       This->data    = xbuf;
1864   } else {
1865       This->datalen = toread+(headerisdata?8:0);
1866       xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
1867       if (!xbuf)
1868           return E_OUTOFMEMORY;
1869
1870       if (headerisdata)
1871           memcpy (xbuf, header, 8);
1872
1873       while (xread < This->datalen) {
1874           ULONG nread;
1875           hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
1876           xread+=nread;
1877           if (hr || !nread)
1878               break;
1879       }
1880       if (xread != This->datalen)
1881           ERR("Could only read %d of %d bytes out of stream?\n",xread,This->datalen);
1882   }
1883   if (This->datalen == 0) { /* Marks the "NONE" picture */
1884       This->desc.picType = PICTYPE_NONE;
1885       return S_OK;
1886   }
1887
1888
1889   /****************************************************************************************
1890    * Part 2: Process the loaded data
1891    */
1892
1893   magic = xbuf[0] + (xbuf[1]<<8);
1894   This->loadtime_format = magic;
1895
1896   switch (magic) {
1897   case BITMAP_FORMAT_GIF: /* GIF */
1898     hr = OLEPictureImpl_LoadGif(This, xbuf, xread);
1899     break;
1900   case BITMAP_FORMAT_JPEG: /* JPEG */
1901     hr = OLEPictureImpl_LoadJpeg(This, xbuf, xread);
1902     break;
1903   case BITMAP_FORMAT_BMP: /* Bitmap */
1904     hr = OLEPictureImpl_LoadDIB(This, xbuf, xread);
1905     break;
1906   case BITMAP_FORMAT_PNG: /* PNG */
1907     hr = OLEPictureImpl_LoadPNG(This, xbuf, xread);
1908     break;
1909   case BITMAP_FORMAT_APM: /* APM */
1910     hr = OLEPictureImpl_LoadAPM(This, xbuf, xread);
1911     break;
1912   case 0x0000: { /* ICON , first word is dwReserved */
1913     hr = OLEPictureImpl_LoadIcon(This, xbuf, xread);
1914     break;
1915   }
1916   default:
1917   {
1918     unsigned int i;
1919
1920     /* let's see if it's a EMF */
1921     hr = OLEPictureImpl_LoadEnhMetafile(This, xbuf, xread);
1922     if (hr == S_OK) break;
1923
1924     FIXME("Unknown magic %04x, %d read bytes:\n",magic,xread);
1925     hr=E_FAIL;
1926     for (i=0;i<xread+8;i++) {
1927         if (i<8) MESSAGE("%02x ",((unsigned char*)header)[i]);
1928         else MESSAGE("%02x ",xbuf[i-8]);
1929         if (i % 10 == 9) MESSAGE("\n");
1930     }
1931     MESSAGE("\n");
1932     break;
1933   }
1934   }
1935   This->bIsDirty = FALSE;
1936
1937   /* FIXME: this notify is not really documented */
1938   if (hr==S_OK)
1939       OLEPicture_SendNotify(This,DISPID_PICT_TYPE);
1940   return hr;
1941 }
1942
1943 static int serializeBMP(HBITMAP hBitmap, void ** ppBuffer, unsigned int * pLength)
1944 {
1945     int iSuccess = 0;
1946     HDC hDC;
1947     BITMAPINFO * pInfoBitmap;
1948     int iNumPaletteEntries;
1949     unsigned char * pPixelData;
1950     BITMAPFILEHEADER * pFileHeader;
1951     BITMAPINFO * pInfoHeader;
1952
1953     pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1954         sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
1955
1956     /* Find out bitmap size and padded length */
1957     hDC = GetDC(0);
1958     pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
1959     GetDIBits(hDC, hBitmap, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
1960
1961     /* Fetch bitmap palette & pixel data */
1962
1963     pPixelData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pInfoBitmap->bmiHeader.biSizeImage);
1964     GetDIBits(hDC, hBitmap, 0, pInfoBitmap->bmiHeader.biHeight, pPixelData, pInfoBitmap, DIB_RGB_COLORS);
1965
1966     /* Calculate the total length required for the BMP data */
1967     if (pInfoBitmap->bmiHeader.biClrUsed != 0) {
1968         iNumPaletteEntries = pInfoBitmap->bmiHeader.biClrUsed;
1969         if (iNumPaletteEntries > 256) iNumPaletteEntries = 256;
1970     } else {
1971         if (pInfoBitmap->bmiHeader.biBitCount <= 8)
1972             iNumPaletteEntries = 1 << pInfoBitmap->bmiHeader.biBitCount;
1973         else
1974             iNumPaletteEntries = 0;
1975     }
1976     *pLength =
1977         sizeof(BITMAPFILEHEADER) +
1978         sizeof(BITMAPINFOHEADER) +
1979         iNumPaletteEntries * sizeof(RGBQUAD) +
1980         pInfoBitmap->bmiHeader.biSizeImage;
1981     *ppBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *pLength);
1982
1983     /* Fill the BITMAPFILEHEADER */
1984     pFileHeader = (BITMAPFILEHEADER *)(*ppBuffer);
1985     pFileHeader->bfType = BITMAP_FORMAT_BMP;
1986     pFileHeader->bfSize = *pLength;
1987     pFileHeader->bfOffBits =
1988         sizeof(BITMAPFILEHEADER) +
1989         sizeof(BITMAPINFOHEADER) +
1990         iNumPaletteEntries * sizeof(RGBQUAD);
1991
1992     /* Fill the BITMAPINFOHEADER and the palette data */
1993     pInfoHeader = (BITMAPINFO *)((unsigned char *)(*ppBuffer) + sizeof(BITMAPFILEHEADER));
1994     memcpy(pInfoHeader, pInfoBitmap, sizeof(BITMAPINFOHEADER) + iNumPaletteEntries * sizeof(RGBQUAD));
1995     memcpy(
1996         (unsigned char *)(*ppBuffer) +
1997             sizeof(BITMAPFILEHEADER) +
1998             sizeof(BITMAPINFOHEADER) +
1999             iNumPaletteEntries * sizeof(RGBQUAD),
2000         pPixelData, pInfoBitmap->bmiHeader.biSizeImage);
2001     iSuccess = 1;
2002
2003     HeapFree(GetProcessHeap(), 0, pPixelData);
2004     HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2005     return iSuccess;
2006 }
2007
2008 static int serializeIcon(HICON hIcon, void ** ppBuffer, unsigned int * pLength)
2009 {
2010         ICONINFO infoIcon;
2011         int iSuccess = 0;
2012
2013         *ppBuffer = NULL; *pLength = 0;
2014         if (GetIconInfo(hIcon, &infoIcon)) {
2015                 HDC hDC;
2016                 BITMAPINFO * pInfoBitmap;
2017                 unsigned char * pIconData = NULL;
2018                 unsigned int iDataSize = 0;
2019
2020         pInfoBitmap = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2021
2022                 /* Find out icon size */
2023                 hDC = GetDC(0);
2024                 pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2025                 GetDIBits(hDC, infoIcon.hbmColor, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2026                 if (1) {
2027                         /* Auxiliary pointers */
2028                         CURSORICONFILEDIR * pIconDir;
2029                         CURSORICONFILEDIRENTRY * pIconEntry;
2030                         BITMAPINFOHEADER * pIconBitmapHeader;
2031                         unsigned int iOffsetPalette;
2032                         unsigned int iOffsetColorData;
2033                         unsigned int iOffsetMaskData;
2034
2035                         unsigned int iLengthScanLineColor;
2036                         unsigned int iLengthScanLineMask;
2037                         unsigned int iNumEntriesPalette;
2038
2039                         iLengthScanLineMask = ((pInfoBitmap->bmiHeader.biWidth + 31) >> 5) << 2;
2040                         iLengthScanLineColor = ((pInfoBitmap->bmiHeader.biWidth * pInfoBitmap->bmiHeader.biBitCount + 31) >> 5) << 2;
2041 /*
2042                         FIXME("DEBUG: bitmap size is %d x %d\n",
2043                                 pInfoBitmap->bmiHeader.biWidth,
2044                                 pInfoBitmap->bmiHeader.biHeight);
2045                         FIXME("DEBUG: bitmap bpp is %d\n",
2046                                 pInfoBitmap->bmiHeader.biBitCount);
2047                         FIXME("DEBUG: bitmap nplanes is %d\n",
2048                                 pInfoBitmap->bmiHeader.biPlanes);
2049                         FIXME("DEBUG: bitmap biSizeImage is %u\n",
2050                                 pInfoBitmap->bmiHeader.biSizeImage);
2051 */
2052                         /* Let's start with one CURSORICONFILEDIR and one CURSORICONFILEDIRENTRY */
2053                         iDataSize += 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY) + sizeof(BITMAPINFOHEADER);
2054                         pIconData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, iDataSize);
2055
2056                         /* Fill out the CURSORICONFILEDIR */
2057                         pIconDir = (CURSORICONFILEDIR *)pIconData;
2058                         pIconDir->idType = 1;
2059                         pIconDir->idCount = 1;
2060
2061                         /* Fill out the CURSORICONFILEDIRENTRY */
2062                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2063                         pIconEntry->bWidth = (unsigned char)pInfoBitmap->bmiHeader.biWidth;
2064                         pIconEntry->bHeight = (unsigned char)pInfoBitmap->bmiHeader.biHeight;
2065                         pIconEntry->bColorCount =
2066                                 (pInfoBitmap->bmiHeader.biBitCount < 8)
2067                                 ? 1 << pInfoBitmap->bmiHeader.biBitCount
2068                                 : 0;
2069                         pIconEntry->xHotspot = pInfoBitmap->bmiHeader.biPlanes;
2070                         pIconEntry->yHotspot = pInfoBitmap->bmiHeader.biBitCount;
2071                         pIconEntry->dwDIBSize = 0;
2072                         pIconEntry->dwDIBOffset = 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY);
2073
2074                         /* Fill out the BITMAPINFOHEADER */
2075                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2076                         *pIconBitmapHeader = pInfoBitmap->bmiHeader;
2077
2078                         /*      Find out whether a palette exists for the bitmap */
2079                         if (    (pInfoBitmap->bmiHeader.biBitCount == 16 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)
2080                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 24)
2081                                 ||      (pInfoBitmap->bmiHeader.biBitCount == 32 && pInfoBitmap->bmiHeader.biCompression == BI_RGB)) {
2082                                 iNumEntriesPalette = pInfoBitmap->bmiHeader.biClrUsed;
2083                                 if (iNumEntriesPalette > 256) iNumEntriesPalette = 256; 
2084                         } else if ((pInfoBitmap->bmiHeader.biBitCount == 16 || pInfoBitmap->bmiHeader.biBitCount == 32)
2085                                 && pInfoBitmap->bmiHeader.biCompression == BI_BITFIELDS) {
2086                                 iNumEntriesPalette = 3;
2087                         } else if (pInfoBitmap->bmiHeader.biBitCount <= 8) {
2088                                 iNumEntriesPalette = 1 << pInfoBitmap->bmiHeader.biBitCount;
2089                         } else {
2090                                 iNumEntriesPalette = 0;
2091                         }
2092
2093                         /*  Add bitmap size and header size to icon data size. */
2094                         iOffsetPalette = iDataSize;
2095                         iDataSize += iNumEntriesPalette * sizeof(DWORD);
2096                         iOffsetColorData = iDataSize;
2097                         iDataSize += pIconBitmapHeader->biSizeImage;
2098                         iOffsetMaskData = iDataSize;
2099                         iDataSize += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2100                         pIconBitmapHeader->biSizeImage += pIconBitmapHeader->biHeight * iLengthScanLineMask;
2101                         pIconBitmapHeader->biHeight *= 2;
2102                         pIconData = HeapReAlloc(GetProcessHeap(), 0, pIconData, iDataSize);
2103                         pIconEntry = (CURSORICONFILEDIRENTRY *)(pIconData + 3 * sizeof(WORD));
2104                         pIconBitmapHeader = (BITMAPINFOHEADER *)(pIconData + 3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2105                         pIconEntry->dwDIBSize = iDataSize - (3 * sizeof(WORD) + sizeof(CURSORICONFILEDIRENTRY));
2106
2107                         /* Get the actual bitmap data from the icon bitmap */
2108                         GetDIBits(hDC, infoIcon.hbmColor, 0, pInfoBitmap->bmiHeader.biHeight,
2109                                 pIconData + iOffsetColorData, pInfoBitmap, DIB_RGB_COLORS);
2110                         if (iNumEntriesPalette > 0) {
2111                                 memcpy(pIconData + iOffsetPalette, pInfoBitmap->bmiColors,
2112                                         iNumEntriesPalette * sizeof(RGBQUAD));
2113                         }
2114
2115                         /* Reset all values so that GetDIBits call succeeds */
2116                         memset(pIconData + iOffsetMaskData, 0, iDataSize - iOffsetMaskData);
2117                         memset(pInfoBitmap, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2118                         pInfoBitmap->bmiHeader.biSize = sizeof(pInfoBitmap->bmiHeader);
2119 /*
2120             if (!(GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS)
2121                                 && GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight,
2122                                         pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS))) {
2123
2124                 printf("ERROR: unable to get bitmap mask (error %u)\n",
2125                                         GetLastError());
2126
2127                         }
2128 */
2129             GetDIBits(hDC, infoIcon.hbmMask, 0, 0, NULL, pInfoBitmap, DIB_RGB_COLORS);
2130             GetDIBits(hDC, infoIcon.hbmMask, 0, pIconEntry->bHeight, pIconData + iOffsetMaskData, pInfoBitmap, DIB_RGB_COLORS);
2131
2132                         /* Write out everything produced so far to the stream */
2133                         *ppBuffer = pIconData; *pLength = iDataSize;
2134                         iSuccess = 1;
2135                 } else {
2136 /*
2137                         printf("ERROR: unable to get bitmap information via GetDIBits() (error %u)\n",
2138                                 GetLastError());
2139 */
2140                 }
2141                 /*
2142                         Remarks (from MSDN entry on GetIconInfo):
2143
2144                         GetIconInfo creates bitmaps for the hbmMask and hbmColor
2145                         members of ICONINFO. The calling application must manage
2146                         these bitmaps and delete them when they are no longer
2147                         necessary.
2148                  */
2149                 if (hDC) ReleaseDC(0, hDC);
2150                 DeleteObject(infoIcon.hbmMask);
2151                 if (infoIcon.hbmColor) DeleteObject(infoIcon.hbmColor);
2152                 HeapFree(GetProcessHeap(), 0, pInfoBitmap);
2153         } else {
2154                 printf("ERROR: Unable to get icon information (error %u)\n",
2155                         GetLastError());
2156         }
2157         return iSuccess;
2158 }
2159
2160 static HRESULT WINAPI OLEPictureImpl_Save(
2161   IPersistStream* iface,IStream*pStm,BOOL fClearDirty)
2162 {
2163     HRESULT hResult = E_NOTIMPL;
2164     void * pIconData;
2165     unsigned int iDataSize;
2166     ULONG dummy;
2167     int iSerializeResult = 0;
2168     OLEPictureImpl *This = impl_from_IPersistStream(iface);
2169
2170     TRACE("%p %p %d\n", This, pStm, fClearDirty);
2171
2172     switch (This->desc.picType) {
2173     case PICTYPE_ICON:
2174         if (This->bIsDirty || !This->data) {
2175             if (!serializeIcon(This->desc.u.icon.hicon, &pIconData, &iDataSize)) {
2176                 ERR("(%p,%p,%d), serializeIcon() failed\n", This, pStm, fClearDirty);
2177                 hResult = E_FAIL;
2178                 break;
2179             }
2180             HeapFree(GetProcessHeap(), 0, This->data);
2181             This->data = pIconData;
2182             This->datalen = iDataSize;
2183         }
2184         if (This->loadtime_magic != 0xdeadbeef) {
2185             DWORD header[2];
2186
2187             header[0] = This->loadtime_magic;
2188             header[1] = This->datalen;
2189             IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2190         }
2191         IStream_Write(pStm, This->data, This->datalen, &dummy);
2192
2193         hResult = S_OK;
2194         break;
2195     case PICTYPE_BITMAP:
2196         if (This->bIsDirty) {
2197             switch (This->keepOrigFormat ? This->loadtime_format : BITMAP_FORMAT_BMP) {
2198             case BITMAP_FORMAT_BMP:
2199                 iSerializeResult = serializeBMP(This->desc.u.bmp.hbitmap, &pIconData, &iDataSize);
2200                 break;
2201             case BITMAP_FORMAT_JPEG:
2202                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format JPEG) not implemented!\n",This,pStm,fClearDirty);
2203                 break;
2204             case BITMAP_FORMAT_GIF:
2205                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format GIF) not implemented!\n",This,pStm,fClearDirty);
2206                 break;
2207             case BITMAP_FORMAT_PNG:
2208                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format PNG) not implemented!\n",This,pStm,fClearDirty);
2209                 break;
2210             default:
2211                 FIXME("(%p,%p,%d), PICTYPE_BITMAP (format UNKNOWN, using BMP?) not implemented!\n",This,pStm,fClearDirty);
2212                 break;
2213             }
2214             if (iSerializeResult) {
2215                 /*
2216                 if (This->loadtime_magic != 0xdeadbeef) {
2217                 */
2218                 if (1) {
2219                     DWORD header[2];
2220
2221                     header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2222                     header[1] = iDataSize;
2223                     IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2224                 }
2225                 IStream_Write(pStm, pIconData, iDataSize, &dummy);
2226
2227                 HeapFree(GetProcessHeap(), 0, This->data);
2228                 This->data = pIconData;
2229                 This->datalen = iDataSize;
2230                 hResult = S_OK;
2231             }
2232         } else {
2233             /*
2234             if (This->loadtime_magic != 0xdeadbeef) {
2235             */
2236             if (1) {
2237                 DWORD header[2];
2238
2239                 header[0] = (This->loadtime_magic != 0xdeadbeef) ? This->loadtime_magic : 0x0000746c;
2240                 header[1] = This->datalen;
2241                 IStream_Write(pStm, header, 2 * sizeof(DWORD), &dummy);
2242             }
2243             IStream_Write(pStm, This->data, This->datalen, &dummy);
2244             hResult = S_OK;
2245         }
2246         break;
2247     case PICTYPE_METAFILE:
2248         FIXME("(%p,%p,%d), PICTYPE_METAFILE not implemented!\n",This,pStm,fClearDirty);
2249         break;
2250     case PICTYPE_ENHMETAFILE:
2251         FIXME("(%p,%p,%d),PICTYPE_ENHMETAFILE not implemented!\n",This,pStm,fClearDirty);
2252         break;
2253     default:
2254         FIXME("(%p,%p,%d), [unknown type] not implemented!\n",This,pStm,fClearDirty);
2255         break;
2256     }
2257     if (hResult == S_OK && fClearDirty) This->bIsDirty = FALSE;
2258     return hResult;
2259 }
2260
2261 static HRESULT WINAPI OLEPictureImpl_GetSizeMax(
2262   IPersistStream* iface,ULARGE_INTEGER*pcbSize)
2263 {
2264   OLEPictureImpl *This = impl_from_IPersistStream(iface);
2265   FIXME("(%p,%p),stub!\n",This,pcbSize);
2266   return E_NOTIMPL;
2267 }
2268
2269
2270 /************************************************************************
2271  *    IDispatch
2272  */
2273
2274 /************************************************************************
2275  * OLEPictureImpl_IDispatch_QueryInterface (IUnknown)
2276  *
2277  * See Windows documentation for more details on IUnknown methods.
2278  */
2279 static HRESULT WINAPI OLEPictureImpl_IDispatch_QueryInterface(
2280   IDispatch* iface,
2281   REFIID     riid,
2282   VOID**     ppvoid)
2283 {
2284   OLEPictureImpl *This = impl_from_IDispatch(iface);
2285
2286   return IPicture_QueryInterface((IPicture *)This, riid, ppvoid);
2287 }
2288
2289 /************************************************************************
2290  * OLEPictureImpl_IDispatch_AddRef (IUnknown)
2291  *
2292  * See Windows documentation for more details on IUnknown methods.
2293  */
2294 static ULONG WINAPI OLEPictureImpl_IDispatch_AddRef(
2295   IDispatch* iface)
2296 {
2297   OLEPictureImpl *This = impl_from_IDispatch(iface);
2298
2299   return IPicture_AddRef((IPicture *)This);
2300 }
2301
2302 /************************************************************************
2303  * OLEPictureImpl_IDispatch_Release (IUnknown)
2304  *
2305  * See Windows documentation for more details on IUnknown methods.
2306  */
2307 static ULONG WINAPI OLEPictureImpl_IDispatch_Release(
2308   IDispatch* iface)
2309 {
2310   OLEPictureImpl *This = impl_from_IDispatch(iface);
2311
2312   return IPicture_Release((IPicture *)This);
2313 }
2314
2315 /************************************************************************
2316  * OLEPictureImpl_GetTypeInfoCount (IDispatch)
2317  *
2318  * See Windows documentation for more details on IDispatch methods.
2319  */
2320 static HRESULT WINAPI OLEPictureImpl_GetTypeInfoCount(
2321   IDispatch*    iface,
2322   unsigned int* pctinfo)
2323 {
2324   TRACE("(%p)\n", pctinfo);
2325
2326   *pctinfo = 1;
2327
2328   return S_OK;
2329 }
2330
2331 /************************************************************************
2332  * OLEPictureImpl_GetTypeInfo (IDispatch)
2333  *
2334  * See Windows documentation for more details on IDispatch methods.
2335  */
2336 static HRESULT WINAPI OLEPictureImpl_GetTypeInfo(
2337   IDispatch*  iface,
2338   UINT      iTInfo,
2339   LCID        lcid,
2340   ITypeInfo** ppTInfo)
2341 {
2342   static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
2343   ITypeLib *tl;
2344   HRESULT hres;
2345
2346   TRACE("(iTInfo=%d, lcid=%04x, %p)\n", iTInfo, (int)lcid, ppTInfo);
2347
2348   if (iTInfo != 0)
2349     return E_FAIL;
2350
2351   hres = LoadTypeLib(stdole2tlb, &tl);
2352   if (FAILED(hres))
2353   {
2354     ERR("Could not load stdole2.tlb\n");
2355     return hres;
2356   }
2357
2358   hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IPictureDisp, ppTInfo);
2359   if (FAILED(hres))
2360     ERR("Did not get IPictureDisp typeinfo from typelib, hres %x\n", hres);
2361
2362   return hres;
2363 }
2364
2365 /************************************************************************
2366  * OLEPictureImpl_GetIDsOfNames (IDispatch)
2367  *
2368  * See Windows documentation for more details on IDispatch methods.
2369  */
2370 static HRESULT WINAPI OLEPictureImpl_GetIDsOfNames(
2371   IDispatch*  iface,
2372   REFIID      riid,
2373   LPOLESTR* rgszNames,
2374   UINT      cNames,
2375   LCID        lcid,
2376   DISPID*     rgDispId)
2377 {
2378   ITypeInfo * pTInfo;
2379   HRESULT hres;
2380
2381   TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", iface, debugstr_guid(riid),
2382         rgszNames, cNames, (int)lcid, rgDispId);
2383
2384   if (cNames == 0)
2385   {
2386     return E_INVALIDARG;
2387   }
2388   else
2389   {
2390     /* retrieve type information */
2391     hres = OLEPictureImpl_GetTypeInfo(iface, 0, lcid, &pTInfo);
2392
2393     if (FAILED(hres))
2394     {
2395       ERR("GetTypeInfo failed.\n");
2396       return hres;
2397     }
2398
2399     /* convert names to DISPIDs */
2400     hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
2401     ITypeInfo_Release(pTInfo);
2402
2403     return hres;
2404   }
2405 }
2406
2407 /************************************************************************
2408  * OLEPictureImpl_Invoke (IDispatch)
2409  *
2410  * See Windows documentation for more details on IDispatch methods.
2411  */
2412 static HRESULT WINAPI OLEPictureImpl_Invoke(
2413   IDispatch*  iface,
2414   DISPID      dispIdMember,
2415   REFIID      riid,
2416   LCID        lcid,
2417   WORD        wFlags,
2418   DISPPARAMS* pDispParams,
2419   VARIANT*    pVarResult,
2420   EXCEPINFO*  pExepInfo,
2421   UINT*     puArgErr)
2422 {
2423   OLEPictureImpl *This = impl_from_IDispatch(iface);
2424
2425   /* validate parameters */
2426
2427   if (!IsEqualIID(riid, &IID_NULL))
2428   {
2429     ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
2430     return DISP_E_UNKNOWNNAME;
2431   }
2432
2433   if (!pDispParams)
2434   {
2435     ERR("null pDispParams not allowed\n");
2436     return DISP_E_PARAMNOTOPTIONAL;
2437   }
2438
2439   if (wFlags & DISPATCH_PROPERTYGET)
2440   {
2441     if (pDispParams->cArgs != 0)
2442     {
2443       ERR("param count for DISPATCH_PROPERTYGET was %d instead of 0\n", pDispParams->cArgs);
2444       return DISP_E_BADPARAMCOUNT;
2445     }
2446     if (!pVarResult)
2447     {
2448       ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
2449       return DISP_E_PARAMNOTOPTIONAL;
2450     }
2451   }
2452   else if (wFlags & DISPATCH_PROPERTYPUT)
2453   {
2454     if (pDispParams->cArgs != 1)
2455     {
2456       ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
2457       return DISP_E_BADPARAMCOUNT;
2458     }
2459   }
2460
2461   switch (dispIdMember)
2462   {
2463   case DISPID_PICT_HANDLE:
2464     if (wFlags & DISPATCH_PROPERTYGET)
2465     {
2466       TRACE("DISPID_PICT_HANDLE\n");
2467       V_VT(pVarResult) = VT_I4;
2468       return IPicture_get_Handle((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2469     }
2470     break;
2471   case DISPID_PICT_HPAL:
2472     if (wFlags & DISPATCH_PROPERTYGET)
2473     {
2474       TRACE("DISPID_PICT_HPAL\n");
2475       V_VT(pVarResult) = VT_I4;
2476       return IPicture_get_hPal((IPicture *)&This->lpVtbl, &V_UINT(pVarResult));
2477     }
2478     else if (wFlags & DISPATCH_PROPERTYPUT)
2479     {
2480       VARIANTARG vararg;
2481       HRESULT hr;
2482       TRACE("DISPID_PICT_HPAL\n");
2483
2484       VariantInit(&vararg);
2485       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I4);
2486       if (FAILED(hr))
2487         return hr;
2488
2489       hr = IPicture_set_hPal((IPicture *)&This->lpVtbl, V_I4(&vararg));
2490
2491       VariantClear(&vararg);
2492       return hr;
2493     }
2494     break;
2495   case DISPID_PICT_TYPE:
2496     if (wFlags & DISPATCH_PROPERTYGET)
2497     {
2498       TRACE("DISPID_PICT_TYPE\n");
2499       V_VT(pVarResult) = VT_I2;
2500       return OLEPictureImpl_get_Type((IPicture *)&This->lpVtbl, &V_I2(pVarResult));
2501     }
2502     break;
2503   case DISPID_PICT_WIDTH:
2504     if (wFlags & DISPATCH_PROPERTYGET)
2505     {
2506       TRACE("DISPID_PICT_WIDTH\n");
2507       V_VT(pVarResult) = VT_I4;
2508       return IPicture_get_Width((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2509     }
2510     break;
2511   case DISPID_PICT_HEIGHT:
2512     if (wFlags & DISPATCH_PROPERTYGET)
2513     {
2514       TRACE("DISPID_PICT_HEIGHT\n");
2515       V_VT(pVarResult) = VT_I4;
2516       return IPicture_get_Height((IPicture *)&This->lpVtbl, &V_I4(pVarResult));
2517     }
2518     break;
2519   }
2520
2521   ERR("invalid dispid 0x%x or wFlags 0x%x\n", dispIdMember, wFlags);
2522   return DISP_E_MEMBERNOTFOUND;
2523 }
2524
2525
2526 static const IPictureVtbl OLEPictureImpl_VTable =
2527 {
2528   OLEPictureImpl_QueryInterface,
2529   OLEPictureImpl_AddRef,
2530   OLEPictureImpl_Release,
2531   OLEPictureImpl_get_Handle,
2532   OLEPictureImpl_get_hPal,
2533   OLEPictureImpl_get_Type,
2534   OLEPictureImpl_get_Width,
2535   OLEPictureImpl_get_Height,
2536   OLEPictureImpl_Render,
2537   OLEPictureImpl_set_hPal,
2538   OLEPictureImpl_get_CurDC,
2539   OLEPictureImpl_SelectPicture,
2540   OLEPictureImpl_get_KeepOriginalFormat,
2541   OLEPictureImpl_put_KeepOriginalFormat,
2542   OLEPictureImpl_PictureChanged,
2543   OLEPictureImpl_SaveAsFile,
2544   OLEPictureImpl_get_Attributes
2545 };
2546
2547 static const IDispatchVtbl OLEPictureImpl_IDispatch_VTable =
2548 {
2549   OLEPictureImpl_IDispatch_QueryInterface,
2550   OLEPictureImpl_IDispatch_AddRef,
2551   OLEPictureImpl_IDispatch_Release,
2552   OLEPictureImpl_GetTypeInfoCount,
2553   OLEPictureImpl_GetTypeInfo,
2554   OLEPictureImpl_GetIDsOfNames,
2555   OLEPictureImpl_Invoke
2556 };
2557
2558 static const IPersistStreamVtbl OLEPictureImpl_IPersistStream_VTable =
2559 {
2560   OLEPictureImpl_IPersistStream_QueryInterface,
2561   OLEPictureImpl_IPersistStream_AddRef,
2562   OLEPictureImpl_IPersistStream_Release,
2563   OLEPictureImpl_GetClassID,
2564   OLEPictureImpl_IsDirty,
2565   OLEPictureImpl_Load,
2566   OLEPictureImpl_Save,
2567   OLEPictureImpl_GetSizeMax
2568 };
2569
2570 static const IConnectionPointContainerVtbl OLEPictureImpl_IConnectionPointContainer_VTable =
2571 {
2572   OLEPictureImpl_IConnectionPointContainer_QueryInterface,
2573   OLEPictureImpl_IConnectionPointContainer_AddRef,
2574   OLEPictureImpl_IConnectionPointContainer_Release,
2575   OLEPictureImpl_EnumConnectionPoints,
2576   OLEPictureImpl_FindConnectionPoint
2577 };
2578
2579 /***********************************************************************
2580  * OleCreatePictureIndirect (OLEAUT32.419)
2581  */
2582 HRESULT WINAPI OleCreatePictureIndirect(LPPICTDESC lpPictDesc, REFIID riid,
2583                             BOOL fOwn, LPVOID *ppvObj )
2584 {
2585   OLEPictureImpl* newPict = NULL;
2586   HRESULT      hr         = S_OK;
2587
2588   TRACE("(%p,%s,%d,%p)\n", lpPictDesc, debugstr_guid(riid), fOwn, ppvObj);
2589
2590   /*
2591    * Sanity check
2592    */
2593   if (ppvObj==0)
2594     return E_POINTER;
2595
2596   *ppvObj = NULL;
2597
2598   /*
2599    * Try to construct a new instance of the class.
2600    */
2601   newPict = OLEPictureImpl_Construct(lpPictDesc, fOwn);
2602
2603   if (newPict == NULL)
2604     return E_OUTOFMEMORY;
2605
2606   /*
2607    * Make sure it supports the interface required by the caller.
2608    */
2609   hr = IPicture_QueryInterface((IPicture*)newPict, riid, ppvObj);
2610
2611   /*
2612    * Release the reference obtained in the constructor. If
2613    * the QueryInterface was unsuccessful, it will free the class.
2614    */
2615   IPicture_Release((IPicture*)newPict);
2616
2617   return hr;
2618 }
2619
2620
2621 /***********************************************************************
2622  * OleLoadPicture (OLEAUT32.418)
2623  */
2624 HRESULT WINAPI OleLoadPicture( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2625                             REFIID riid, LPVOID *ppvObj )
2626 {
2627   LPPERSISTSTREAM ps;
2628   IPicture      *newpic;
2629   HRESULT hr;
2630
2631   TRACE("(%p,%d,%d,%s,%p), partially implemented.\n",
2632         lpstream, lSize, fRunmode, debugstr_guid(riid), ppvObj);
2633
2634   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2635   if (hr)
2636     return hr;
2637   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2638   if (hr) {
2639       ERR("Could not get IPersistStream iface from Ole Picture?\n");
2640       IPicture_Release(newpic);
2641       *ppvObj = NULL;
2642       return hr;
2643   }
2644   hr = IPersistStream_Load(ps,lpstream);
2645   IPersistStream_Release(ps);
2646   if (FAILED(hr))
2647   {
2648       ERR("IPersistStream_Load failed\n");
2649       IPicture_Release(newpic);
2650       *ppvObj = NULL;
2651       return hr;
2652   }
2653   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2654   if (hr)
2655       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2656   IPicture_Release(newpic);
2657   return hr;
2658 }
2659
2660 /***********************************************************************
2661  * OleLoadPictureEx (OLEAUT32.401)
2662  */
2663 HRESULT WINAPI OleLoadPictureEx( LPSTREAM lpstream, LONG lSize, BOOL fRunmode,
2664                             REFIID riid, DWORD xsiz, DWORD ysiz, DWORD flags, LPVOID *ppvObj )
2665 {
2666   LPPERSISTSTREAM ps;
2667   IPicture      *newpic;
2668   HRESULT hr;
2669
2670   FIXME("(%p,%d,%d,%s,x=%d,y=%d,f=%x,%p), partially implemented.\n",
2671         lpstream, lSize, fRunmode, debugstr_guid(riid), xsiz, ysiz, flags, ppvObj);
2672
2673   hr = OleCreatePictureIndirect(NULL,riid,!fRunmode,(LPVOID*)&newpic);
2674   if (hr)
2675     return hr;
2676   hr = IPicture_QueryInterface(newpic,&IID_IPersistStream, (LPVOID*)&ps);
2677   if (hr) {
2678       ERR("Could not get IPersistStream iface from Ole Picture?\n");
2679       IPicture_Release(newpic);
2680       *ppvObj = NULL;
2681       return hr;
2682   }
2683   hr = IPersistStream_Load(ps,lpstream);
2684   IPersistStream_Release(ps);
2685   if (FAILED(hr))
2686   {
2687       ERR("IPersistStream_Load failed\n");
2688       IPicture_Release(newpic);
2689       *ppvObj = NULL;
2690       return hr;
2691   }
2692   hr = IPicture_QueryInterface(newpic,riid,ppvObj);
2693   if (hr)
2694       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2695   IPicture_Release(newpic);
2696   return hr;
2697 }
2698
2699 /***********************************************************************
2700  * OleLoadPicturePath (OLEAUT32.424)
2701  */
2702 HRESULT WINAPI OleLoadPicturePath( LPOLESTR szURLorPath, LPUNKNOWN punkCaller,
2703                 DWORD dwReserved, OLE_COLOR clrReserved, REFIID riid,
2704                 LPVOID *ppvRet )
2705 {
2706   static const WCHAR file[] = { 'f','i','l','e',':','/','/',0 };
2707   IPicture *ipicture;
2708   HANDLE hFile;
2709   DWORD dwFileSize;
2710   HGLOBAL hGlobal = NULL;
2711   DWORD dwBytesRead = 0;
2712   IStream *stream;
2713   BOOL bRead;
2714   IPersistStream *pStream;
2715   HRESULT hRes;
2716
2717   TRACE("(%s,%p,%d,%08x,%s,%p): stub\n",
2718         debugstr_w(szURLorPath), punkCaller, dwReserved, clrReserved,
2719         debugstr_guid(riid), ppvRet);
2720
2721   if (!ppvRet) return E_POINTER;
2722
2723   if (strncmpW(szURLorPath, file, 7) == 0) {        
2724       szURLorPath += 7;
2725   
2726       hFile = CreateFileW(szURLorPath, GENERIC_READ, 0, NULL, OPEN_EXISTING,
2727                                    0, NULL);
2728       if (hFile == INVALID_HANDLE_VALUE)
2729           return E_UNEXPECTED;
2730
2731       dwFileSize = GetFileSize(hFile, NULL);
2732       if (dwFileSize != INVALID_FILE_SIZE )
2733       {
2734           hGlobal = GlobalAlloc(GMEM_FIXED,dwFileSize);
2735           if ( hGlobal)
2736           {
2737               bRead = ReadFile(hFile, hGlobal, dwFileSize, &dwBytesRead, NULL);
2738               if (!bRead)
2739               {
2740                   GlobalFree(hGlobal);
2741                   hGlobal = 0;
2742               }
2743           }
2744       }
2745       CloseHandle(hFile);
2746       
2747       if (!hGlobal)
2748           return E_UNEXPECTED;
2749
2750       hRes = CreateStreamOnHGlobal(hGlobal, TRUE, &stream);
2751       if (FAILED(hRes)) 
2752       {
2753           GlobalFree(hGlobal);
2754           return hRes;
2755       }
2756   } else {
2757       IMoniker *pmnk;
2758       IBindCtx *pbc;
2759
2760       hRes = CreateBindCtx(0, &pbc);
2761       if (SUCCEEDED(hRes)) 
2762       {
2763           hRes = CreateURLMoniker(NULL, szURLorPath, &pmnk);
2764           if (SUCCEEDED(hRes))
2765           {              
2766               hRes = IMoniker_BindToStorage(pmnk, pbc, NULL, &IID_IStream, (LPVOID*)&stream);
2767               IMoniker_Release(pmnk);
2768           }
2769           IBindCtx_Release(pbc);
2770       }
2771       if (FAILED(hRes))
2772           return hRes;
2773   }
2774
2775   hRes = CoCreateInstance(&CLSID_StdPicture, punkCaller, CLSCTX_INPROC_SERVER, 
2776                    &IID_IPicture, (LPVOID*)&ipicture);
2777   if (hRes != S_OK) {
2778       IStream_Release(stream);
2779       return hRes;
2780   }
2781   
2782   hRes = IPicture_QueryInterface(ipicture, &IID_IPersistStream, (LPVOID*)&pStream);
2783   if (hRes) {
2784       IStream_Release(stream);
2785       IPicture_Release(ipicture);
2786       return hRes;
2787   }
2788
2789   hRes = IPersistStream_Load(pStream, stream); 
2790   IPersistStream_Release(pStream);
2791   IStream_Release(stream);
2792
2793   if (hRes) {
2794       IPicture_Release(ipicture);
2795       return hRes;
2796   }
2797
2798   hRes = IPicture_QueryInterface(ipicture,riid,ppvRet);
2799   if (hRes)
2800       ERR("Failed to get interface %s from IPicture.\n",debugstr_guid(riid));
2801   
2802   IPicture_Release(ipicture);
2803   return hRes;
2804 }
2805
2806 /*******************************************************************************
2807  * StdPic ClassFactory
2808  */
2809 typedef struct
2810 {
2811     /* IUnknown fields */
2812     const IClassFactoryVtbl    *lpVtbl;
2813     LONG                        ref;
2814 } IClassFactoryImpl;
2815
2816 static HRESULT WINAPI
2817 SPCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) {
2818         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2819
2820         FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj);
2821         return E_NOINTERFACE;
2822 }
2823
2824 static ULONG WINAPI
2825 SPCF_AddRef(LPCLASSFACTORY iface) {
2826         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2827         return InterlockedIncrement(&This->ref);
2828 }
2829
2830 static ULONG WINAPI SPCF_Release(LPCLASSFACTORY iface) {
2831         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2832         /* static class, won't be  freed */
2833         return InterlockedDecrement(&This->ref);
2834 }
2835
2836 static HRESULT WINAPI SPCF_CreateInstance(
2837         LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2838 ) {
2839     /* Creates an uninitialized picture */
2840     return OleCreatePictureIndirect(NULL,riid,TRUE,ppobj);
2841
2842 }
2843
2844 static HRESULT WINAPI SPCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2845         IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
2846         FIXME("(%p)->(%d),stub!\n",This,dolock);
2847         return S_OK;
2848 }
2849
2850 static const IClassFactoryVtbl SPCF_Vtbl = {
2851         SPCF_QueryInterface,
2852         SPCF_AddRef,
2853         SPCF_Release,
2854         SPCF_CreateInstance,
2855         SPCF_LockServer
2856 };
2857 static IClassFactoryImpl STDPIC_CF = {&SPCF_Vtbl, 1 };
2858
2859 void _get_STDPIC_CF(LPVOID *ppv) { *ppv = (LPVOID)&STDPIC_CF; }