crypt32: Introduce function to encode an array of items as a set.
[wine] / dlls / ddraw / surface.c
1 /* DirectDraw Surface Implementation
2  *
3  * Copyright (c) 1997-2000 Marcus Meissner
4  * Copyright (c) 1998-2000 Lionel Ulmer
5  * Copyright (c) 2000-2001 TransGaming Technologies Inc.
6  * Copyright (c) 2006 Stefan Dösinger
7  *
8  * This file contains the (internal) driver registration functions,
9  * driver enumeration APIs and DirectDraw creation functions.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <stdlib.h>
33
34 #define COBJMACROS
35 #define NONAMELESSUNION
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winerror.h"
40 #include "wingdi.h"
41 #include "wine/exception.h"
42
43 #include "ddraw.h"
44 #include "d3d.h"
45
46 #include "ddraw_private.h"
47 #include "wine/debug.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
50
51 /*****************************************************************************
52  * IUnknown parts follow
53  *****************************************************************************/
54
55 /*****************************************************************************
56  * IDirectDrawSurface7::QueryInterface
57  *
58  * A normal QueryInterface implementation. For QueryInterface rules
59  * see ddraw.c, IDirectDraw7::QueryInterface. This method
60  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
61  * in all versions, the IDirectDrawGammaControl interface and it can
62  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
63  *
64  * Params:
65  *  riid: The interface id queried for
66  *  obj: Address to write the pointer to
67  *
68  * Returns:
69  *  S_OK on success
70  *  E_NOINTERFACE if the requested interface wasn't found
71  *
72  *****************************************************************************/
73 static HRESULT WINAPI
74 IDirectDrawSurfaceImpl_QueryInterface(IDirectDrawSurface7 *iface,
75                                       REFIID riid,
76                                       void **obj)
77 {
78     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
79
80     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
81     *obj = NULL;
82
83     if(!riid)
84         return DDERR_INVALIDPARAMS;
85
86     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),obj);
87     if (IsEqualGUID(riid, &IID_IUnknown)
88      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
89      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
90     {
91         IUnknown_AddRef(iface);
92         *obj = ICOM_INTERFACE(This, IDirectDrawSurface7);
93         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
94         return S_OK;
95     }
96     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
97           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
98           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
99     {
100         IUnknown_AddRef(iface);
101         *obj = ICOM_INTERFACE(This, IDirectDrawSurface3);
102         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
103         return S_OK;
104     }
105     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
106     {
107         IUnknown_AddRef(iface);
108         *obj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
109         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
110         return S_OK;
111     }
112     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
113              IsEqualGUID(riid, &IID_IDirect3DHALDevice)||
114              IsEqualGUID(riid, &IID_IDirect3DRGBDevice) )
115     {
116         IDirect3DDevice7 *d3d;
117
118         /* Call into IDirect3D7 for creation */
119         IDirect3D7_CreateDevice(ICOM_INTERFACE(This->ddraw, IDirect3D7),
120                                 riid,
121                                 ICOM_INTERFACE(This, IDirectDrawSurface7),
122                                 &d3d);
123
124         *obj = COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice7, IDirect3DDevice, d3d);
125         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
126
127         return S_OK;
128     }
129     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
130              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
131     {
132         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
133         {
134             *obj = ICOM_INTERFACE(This, IDirect3DTexture);
135             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
136         }
137         else
138         {
139             *obj = ICOM_INTERFACE(This, IDirect3DTexture2);
140             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
141         }
142         IUnknown_AddRef( (IUnknown *) *obj);
143         return S_OK;
144     }
145
146     ERR("No interface\n");
147     return E_NOINTERFACE;
148 }
149
150 /*****************************************************************************
151  * IDirectDrawSurface7::AddRef
152  *
153  * A normal addref implementation
154  *
155  * Returns:
156  *  The new refcount
157  *
158  *****************************************************************************/
159 static ULONG WINAPI
160 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
161 {
162     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
163     ULONG refCount = InterlockedIncrement(&This->ref);
164
165     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
166     return refCount;
167 }
168
169 /*****************************************************************************
170  * IDirectDrawSurfaceImpl_Destroy
171  *
172  * A helper function for IDirectDrawSurface7::Release
173  *
174  * Frees the surface, regardless of its refcount.
175  *  See IDirectDrawSurface7::Release for more information
176  *
177  * Params:
178  *  This: Surface to free
179  *
180  *****************************************************************************/
181 static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
182 {
183     TRACE("(%p)\n", This);
184
185     /* Check the refcount and give a warning */
186     if(This->ref > 1)
187     {
188         /* This can happen when a complex surface is destroyed,
189          * because the 2nd surface was addref()ed when the app
190          * called GetAttachedSurface
191          */
192         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
193     }
194
195     /* Check for attached surfaces and detach them */
196     if(This->first_attached != This)
197     {
198         /* Well, this shouldn't happen: The surface being attached is addref()ed
199           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
200           * is called, because the refcount is held. It looks like the app released()
201           * it often enough to force this
202           */
203         IDirectDrawSurface7 *root = ICOM_INTERFACE(This->first_attached, IDirectDrawSurface7);
204         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This, IDirectDrawSurface7);
205
206         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
207
208         /* The refcount will drop to -1 here */
209         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
210         {
211             ERR("(%p) DeleteAttachedSurface failed!\n", This);
212         }
213     }
214
215     while(This->next_attached != NULL)
216     {
217         IDirectDrawSurface7 *root = ICOM_INTERFACE(This, IDirectDrawSurface7);
218         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This->next_attached, IDirectDrawSurface7);
219
220         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
221         {
222             ERR("(%p) DeleteAttachedSurface failed!\n", This);
223             assert(0);
224         }
225     }
226
227     /* Now destroy the surface. Wait: It could have been released if we are a texture */
228     if(This->WineD3DSurface)
229         IWineD3DSurface_Release(This->WineD3DSurface);
230
231     /* Having a texture handle set implies that the device still exists */
232     if(This->Handle)
233     {
234         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
235         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
236     }
237
238     /* Reduce the ddraw surface count */
239     InterlockedDecrement(&This->ddraw->surfaces);
240     list_remove(&This->surface_list_entry);
241
242     HeapFree(GetProcessHeap(), 0, This);
243 }
244
245 /*****************************************************************************
246  * IDirectDrawSurface7::Release
247  *
248  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
249  * surface is destroyed.
250  *
251  * Destroying the surface is a bit tricky. For the connection between
252  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
253  * It has a nice graph explaining the connection.
254  *
255  * What happens here is basically this:
256  * When a surface is destroyed, its WineD3DSurface is released,
257  * and the refcount of the DirectDraw interface is reduced by 1. If it has
258  * complex surfaces attached to it, then these surfaces are destroyed too,
259  * regardless of their refcount. If any surface being destroyed has another
260  * surface attached to it (with a "soft" attachment, not complex), then
261  * this surface is detached with DeleteAttachedSurface.
262  *
263  * When the surface is a texture, the WineD3DTexture is released.
264  * If the surface is the Direct3D render target, then the D3D
265  * capabilities of the WineD3DDevice are uninitialized, which causes the
266  * swapchain to be released.
267  *
268  * When a complex sublevel falls to ref zero, then this is ignored.
269  *
270  * Returns:
271  *  The new refcount
272  *
273  *****************************************************************************/
274 static ULONG WINAPI
275 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
276 {
277     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
278     ULONG ref;
279     TRACE("(%p) : Releasing from %d\n", This, This->ref);
280     ref = InterlockedDecrement(&This->ref);
281
282     if (ref == 0)
283     {
284
285         IDirectDrawSurfaceImpl *surf;
286         IDirectDrawImpl *ddraw;
287         IUnknown *ifaceToRelease = This->ifaceToRelease;
288         int i;
289
290         /* Complex attached surfaces are destroyed implicitely when the root is released */
291         EnterCriticalSection(&ddraw_cs);
292         if(!This->is_complex_root)
293         {
294             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
295             LeaveCriticalSection(&ddraw_cs);
296             return ref;
297         }
298         ddraw = This->ddraw;
299
300         /* If it's a texture, destroy the WineD3DTexture.
301          * WineD3D will destroy the IParent interfaces
302          * of the sublevels, which destroys the WineD3DSurfaces.
303          * Set the surfaces to NULL to avoid destroying them again later
304          */
305         if(This->wineD3DTexture)
306         {
307             IWineD3DBaseTexture_Release(This->wineD3DTexture);
308         }
309         /* If it's the RenderTarget, destroy the d3ddevice */
310         else if( (ddraw->d3d_initialized) && (This == ddraw->d3d_target))
311         {
312             TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
313
314             /* Unset any index buffer, just to be sure */
315             IWineD3DDevice_SetIndices(ddraw->wineD3DDevice, NULL);
316             IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
317
318             if(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroyDepthStencilSurface, D3D7CB_DestroySwapChain) != D3D_OK)
319             {
320                 /* Not good */
321                 ERR("(%p) Failed to uninit 3D\n", This);
322             }
323             else
324             {
325                 /* Free the d3d window if one was created */
326                 if(ddraw->d3d_window != 0)
327                 {
328                     TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
329                     DestroyWindow(ddraw->d3d_window);
330                     ddraw->d3d_window = 0;
331                 }
332                 /* Unset the pointers */
333             }
334
335             ddraw->d3d_initialized = FALSE;
336             ddraw->d3d_target = NULL;
337
338             /* Write a trace because D3D unloading was the reason for many
339              * crashes during development.
340              */
341             TRACE("(%p) D3D unloaded\n", This);
342         }
343         else if(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
344                                                      DDSCAPS_3DDEVICE       |
345                                                      DDSCAPS_TEXTURE        ) )
346         {
347             /* It's a render target, but no swapchain was created.
348              * The IParent interfaces have to be released manually.
349              * The same applies for textures without an
350              * IWineD3DTexture object attached
351              */
352             IParent *Parent;
353
354             for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
355             {
356                 if(This->complex_array[i])
357                 {
358                     /* Only the topmost level can have more than 1 surfaces in the complex
359                      * attachment array(Cube texture roots), for all others there is only
360                      * one
361                      */
362                     surf = This->complex_array[i];
363                     while(surf)
364                     {
365                         IWineD3DSurface_GetParent(surf->WineD3DSurface,
366                                                   (IUnknown **) &Parent);
367                         IParent_Release(Parent);  /* For the getParent */
368                         IParent_Release(Parent);  /* To release it */
369                         surf = surf->complex_array[0];
370                     }
371                 }
372             }
373
374             /* Now the top-level surface */
375             IWineD3DSurface_GetParent(This->WineD3DSurface,
376                                       (IUnknown **) &Parent);
377             IParent_Release(Parent);  /* For the getParent */
378             IParent_Release(Parent);  /* To release it */
379         }
380
381         /* The refcount test shows that the palette is detached when the surface is destroyed */
382         IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
383                                                       NULL);
384
385         /* Loop through all complex attached surfaces,
386          * and destroy them.
387          *
388          * Yet again, only the root can have more than one complexly attached surface, all the others
389          * have a total of one;
390          */
391         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
392         {
393             if(!This->complex_array[i]) break;
394
395             surf = This->complex_array[i];
396             This->complex_array[i] = NULL;
397             while(surf)
398             {
399                 IDirectDrawSurfaceImpl *destroy = surf;
400                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
401                 IDirectDrawSurfaceImpl_Destroy(destroy);    /* Destroy it */
402             }
403         }
404
405         /* Destroy the root surface.
406          */
407         IDirectDrawSurfaceImpl_Destroy(This);
408
409         /* Reduce the ddraw refcount */
410         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
411         LeaveCriticalSection(&ddraw_cs);
412     }
413
414     return ref;
415 }
416
417 /*****************************************************************************
418  * IDirectDrawSurface7::GetAttachedSurface
419  *
420  * Returns an attached surface with the requested caps. Surface attachment
421  * and complex surfaces are not clearly described by the MSDN or sdk,
422  * so this method is tricky and likely to contain problems.
423  * This implementation searches the complex list first, then the
424  * attachment chain.
425  *
426  * The chains are searched from This down to the last surface in the chain,
427  * not from the first element in the chain. The first surface found is
428  * returned. The MSDN says that this method fails if more than one surface
429  * matches the caps, but it is not sure if that is right. The attachment
430  * structure may not even allow two matching surfaces.
431  *
432  * The found surface is AddRef-ed before it is returned.
433  *
434  * Params:
435  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
436  *  Surface: Address to store the found surface
437  *
438  * Returns:
439  *  DD_OK on success
440  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
441  *  DDERR_NOTFOUND if no surface was found
442  *
443  *****************************************************************************/
444 static HRESULT WINAPI
445 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
446                                           DDSCAPS2 *Caps,
447                                           IDirectDrawSurface7 **Surface)
448 {
449     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
450     IDirectDrawSurfaceImpl *surf;
451     DDSCAPS2 our_caps;
452     int i;
453
454     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
455     EnterCriticalSection(&ddraw_cs);
456
457     our_caps = *Caps;
458
459     if(This->version < 7)
460     {
461         /* Earlier dx apps put garbage into these members, clear them */
462         our_caps.dwCaps2 = 0;
463         our_caps.dwCaps3 = 0;
464         our_caps.dwCaps4 = 0;
465     }
466
467     TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */
468
469     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
470     {
471         surf = This->complex_array[i];
472         if(!surf) break;
473
474         if (TRACE_ON(ddraw))
475         {
476             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
477                    surf->surface_desc.ddsCaps.dwCaps,
478                    surf->surface_desc.ddsCaps.dwCaps2,
479                    surf->surface_desc.ddsCaps.dwCaps3,
480                    surf->surface_desc.ddsCaps.dwCaps4);
481         }
482
483         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
484             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
485
486             /* MSDN: "This method fails if more than one surface is attached
487              * that matches the capabilities requested."
488              *
489              * Not sure how to test this.
490              */
491
492             TRACE("(%p): Returning surface %p\n", This, surf);
493             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
494             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
495             IDirectDrawSurface7_AddRef(*Surface);
496             LeaveCriticalSection(&ddraw_cs);
497             return DD_OK;
498         }
499     }
500
501     /* Next, look at the attachment chain */
502     surf = This;
503
504     while( (surf = surf->next_attached) )
505     {
506         if (TRACE_ON(ddraw))
507         {
508             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
509                    surf->surface_desc.ddsCaps.dwCaps,
510                    surf->surface_desc.ddsCaps.dwCaps2,
511                    surf->surface_desc.ddsCaps.dwCaps3,
512                    surf->surface_desc.ddsCaps.dwCaps4);
513         }
514
515         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
516             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
517
518             TRACE("(%p): Returning surface %p\n", This, surf);
519             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
520             IDirectDrawSurface7_AddRef(*Surface);
521             LeaveCriticalSection(&ddraw_cs);
522             return DD_OK;
523         }
524     }
525
526     TRACE("(%p) Didn't find a valid surface\n", This);
527     LeaveCriticalSection(&ddraw_cs);
528     return DDERR_NOTFOUND;
529 }
530
531 /*****************************************************************************
532  * IDirectDrawSurface7::Lock
533  *
534  * Locks the surface and returns a pointer to the surface's memory
535  *
536  * Params:
537  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
538  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
539  *  Flags: Locking flags, e.g Read only or write only
540  *  h: An event handle that's not used and must be NULL
541  *
542  * Returns:
543  *  DD_OK on success
544  *  DDERR_INVALIDPARAMS if DDSD is NULL
545  *  For more details, see IWineD3DSurface::LockRect
546  *
547  *****************************************************************************/
548 static HRESULT WINAPI
549 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
550                             RECT *Rect,
551                             DDSURFACEDESC2 *DDSD,
552                             DWORD Flags,
553                             HANDLE h)
554 {
555     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
556     WINED3DLOCKED_RECT LockedRect;
557     HRESULT hr;
558     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
559
560     if(!DDSD)
561         return DDERR_INVALIDPARAMS;
562
563     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
564     EnterCriticalSection(&ddraw_cs);
565     if (Rect)
566     {
567         if ((Rect->left < 0)
568                 || (Rect->top < 0)
569                 || (Rect->left > Rect->right)
570                 || (Rect->top > Rect->bottom)
571                 || (Rect->right > This->surface_desc.dwWidth)
572                 || (Rect->bottom > This->surface_desc.dwHeight))
573         {
574             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
575             LeaveCriticalSection(&ddraw_cs);
576             return DDERR_INVALIDPARAMS;
577         }
578     }
579
580     /* Should I check for the handle to be NULL?
581      *
582      * The DDLOCK flags and the D3DLOCK flags are equal
583      * for the supported values. The others are ignored by WineD3D
584      */
585
586     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
587        DDSD->dwSize != sizeof(DDSURFACEDESC2))
588     {
589         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
590         LeaveCriticalSection(&ddraw_cs);
591         return DDERR_INVALIDPARAMS;
592     }
593
594     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
595                                   &LockedRect,
596                                   Rect,
597                                   Flags);
598     if(hr != D3D_OK)
599     {
600         LeaveCriticalSection(&ddraw_cs);
601         return hr;
602     }
603
604     /* Override the memory area. The pitch should be set already. Strangely windows
605      * does not set the LPSURFACE flag on locked surfaces !?!.
606      * DDSD->dwFlags |= DDSD_LPSURFACE;
607      */
608     This->surface_desc.lpSurface = LockedRect.pBits;
609     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
610
611     TRACE("locked surface returning description :\n");
612     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
613
614     LeaveCriticalSection(&ddraw_cs);
615     return DD_OK;
616 }
617
618 /*****************************************************************************
619  * IDirectDrawSurface7::Unlock
620  *
621  * Unlocks an locked surface
622  *
623  * Params:
624  *  Rect: Not used by this implementation
625  *
626  * Returns:
627  *  D3D_OK on success
628  *  For more details, see IWineD3DSurface::UnlockRect
629  *
630  *****************************************************************************/
631 static HRESULT WINAPI
632 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
633                               RECT *pRect)
634 {
635     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
636     HRESULT hr;
637     TRACE("(%p)->(%p)\n", This, pRect);
638
639     EnterCriticalSection(&ddraw_cs);
640     hr = IWineD3DSurface_UnlockRect(This->WineD3DSurface);
641     if(SUCCEEDED(hr))
642     {
643         This->surface_desc.lpSurface = NULL;
644     }
645     LeaveCriticalSection(&ddraw_cs);
646     return hr;
647 }
648
649 /*****************************************************************************
650  * IDirectDrawSurface7::Flip
651  *
652  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
653  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
654  * the flip target is passed to WineD3D, even if the app didn't specify one
655  *
656  * Params:
657  *  DestOverride: Specifies the surface that will become the new front
658  *                buffer. If NULL, the current back buffer is used
659  *  Flags: some DirectDraw flags, see include/ddraw.h
660  *
661  * Returns:
662  *  DD_OK on success
663  *  DDERR_NOTFLIPPABLE if no flip target could be found
664  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
665  *  For more details, see IWineD3DSurface::Flip
666  *
667  *****************************************************************************/
668 static HRESULT WINAPI
669 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
670                             IDirectDrawSurface7 *DestOverride,
671                             DWORD Flags)
672 {
673     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
674     IDirectDrawSurfaceImpl *Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DestOverride);
675     IDirectDrawSurface7 *Override7;
676     HRESULT hr;
677     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
678
679     /* Flip has to be called from a front buffer
680      * What about overlay surfaces, AFAIK they can flip too?
681      */
682     if( !(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) )
683         return DDERR_INVALIDOBJECT; /* Unckecked */
684
685     EnterCriticalSection(&ddraw_cs);
686
687     /* WineD3D doesn't keep track of attached surface, so find the target */
688     if(!Override)
689     {
690         DDSCAPS2 Caps;
691
692         memset(&Caps, 0, sizeof(Caps));
693         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
694         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
695         if(hr != DD_OK)
696         {
697             ERR("Can't find a flip target\n");
698             LeaveCriticalSection(&ddraw_cs);
699             return DDERR_NOTFLIPPABLE; /* Unchecked */
700         }
701         Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Override7);
702
703         /* For the GetAttachedSurface */
704         IDirectDrawSurface7_Release(Override7);
705     }
706
707     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
708                               Override->WineD3DSurface,
709                               Flags);
710     LeaveCriticalSection(&ddraw_cs);
711     return hr;
712 }
713
714 /*****************************************************************************
715  * IDirectDrawSurface7::Blt
716  *
717  * Performs a blit on the surface
718  *
719  * Params:
720  *  DestRect: Destination rectangle, can be NULL
721  *  SrcSurface: Source surface, can be NULL
722  *  SrcRect: Source rectange, can be NULL
723  *  Flags: Blt flags
724  *  DDBltFx: Some extended blt parameters, connected to the flags
725  *
726  * Returns:
727  *  D3D_OK on success
728  *  See IWineD3DSurface::Blt for more details
729  *
730  *****************************************************************************/
731 static HRESULT WINAPI
732 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
733                            RECT *DestRect,
734                            IDirectDrawSurface7 *SrcSurface,
735                            RECT *SrcRect,
736                            DWORD Flags,
737                            DDBLTFX *DDBltFx)
738 {
739     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
740     HRESULT hr;
741     IDirectDrawSurfaceImpl *Src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, SrcSurface);
742     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
743
744     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
745      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
746      */
747     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
748         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
749         return DDERR_INVALIDPARAMS;
750     }
751
752     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
753         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
754         return DDERR_INVALIDPARAMS;
755     }
756
757     /* Sizes can change, therefore hold the lock when testing the rectangles */
758     EnterCriticalSection(&ddraw_cs);
759     if(DestRect)
760     {
761         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
762            DestRect->right > This->surface_desc.dwWidth ||
763            DestRect->bottom > This->surface_desc.dwHeight)
764         {
765             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
766             LeaveCriticalSection(&ddraw_cs);
767             return DDERR_INVALIDRECT;
768         }
769     }
770     if(Src && SrcRect)
771     {
772         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
773            SrcRect->right > Src->surface_desc.dwWidth ||
774            SrcRect->bottom > Src->surface_desc.dwHeight)
775         {
776             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
777             LeaveCriticalSection(&ddraw_cs);
778             return DDERR_INVALIDRECT;
779         }
780     }
781
782     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
783         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
784         LeaveCriticalSection(&ddraw_cs);
785         return DDERR_INVALIDPARAMS;
786     }
787
788     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
789      * and replace the ddraw surfaces with the wined3d surfaces
790      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
791      */
792     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
793                              DestRect,
794                              Src ? Src->WineD3DSurface : NULL,
795                              SrcRect,
796                              Flags,
797                              (WINEDDBLTFX *) DDBltFx,
798                              WINED3DTEXF_POINT);
799
800     LeaveCriticalSection(&ddraw_cs);
801     switch(hr)
802     {
803         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
804         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
805         default:                            return hr;
806     }
807 }
808
809 /*****************************************************************************
810  * IDirectDrawSurface7::AddAttachedSurface
811  *
812  * Attaches a surface to another surface. How the surface attachments work
813  * is not totally understood yet, and this method is prone to problems.
814  * he surface that is attached is AddRef-ed.
815  *
816  * Tests with complex surfaces suggest that the surface attachments form a
817  * tree, but no method to test this has been found yet.
818  *
819  * The attachment list consists of a first surface (first_attached) and
820  * for each surface a pointer to the next attached surface (next_attached).
821  * For the first surface, and a surface that has no attachments
822  * first_attached points to the surface itself. A surface that has
823  * no successors in the chain has next_attached set to NULL.
824  *
825  * Newly attached surfaces are attached right after the root surface.
826  * If a surface is attached to a complex surface compound, it's attached to
827  * the surface that the app requested, not the complex root. See
828  * GetAttachedSurface for a description how surfaces are found.
829  *
830  * This is how the current implementation works, and it was coded by looking
831  * at the needs of the applications.
832  *
833  * So far only Z-Buffer attachments are tested, and they are activated in
834  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
835  * Back buffers should work in 2D mode, but they are not tested(They can be
836  * attached in older iface versions). Rendering to the front buffer and
837  * switching between that and double buffering is not yet implemented in
838  * WineD3D, so for 3D it might have unexpected results.
839  *
840  * IDirectDrawSurfaceImpl_AddAttachedSurface is the real thing,
841  * IDirectDrawSurface7Impl_AddAttachedSurface is a wrapper around it that
842  * performs additional checks. Version 7 of this interface is much more restrictive
843  * than its predecessors.
844  *
845  * Params:
846  *  Attach: Surface to attach to iface
847  *
848  * Returns:
849  *  DD_OK on success
850  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
851  *
852  *****************************************************************************/
853 HRESULT WINAPI
854 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurfaceImpl *This,
855                                           IDirectDrawSurfaceImpl *Surf)
856 {
857     TRACE("(%p)->(%p)\n", This, Surf);
858
859     if(Surf == This)
860         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
861
862     EnterCriticalSection(&ddraw_cs);
863
864     /* Check if the surface is already attached somewhere */
865     if( (Surf->next_attached != NULL) ||
866         (Surf->first_attached != Surf) )
867     {
868         /* TODO: Test for the structure of the manual attachment. Is it a chain or a list?
869          * What happens if one surface is attached to 2 different surfaces?
870          */
871         FIXME("(%p) The Surface %p is already attached somewhere else: next_attached = %p, first_attached = %p, can't handle by now\n", This, Surf, Surf->next_attached, Surf->first_attached);
872         LeaveCriticalSection(&ddraw_cs);
873         return DDERR_SURFACEALREADYATTACHED;
874     }
875
876     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
877     Surf->next_attached = This->next_attached;
878     Surf->first_attached = This->first_attached;
879     This->next_attached = Surf;
880
881     /* Check if the WineD3D depth stencil needs updating */
882     if(This->ddraw->d3ddevice)
883     {
884         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
885     }
886
887     /* MSDN: 
888      * "This method increments the reference count of the surface being attached."
889      */
890     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(Surf, IDirectDrawSurface7));
891     LeaveCriticalSection(&ddraw_cs);
892     return DD_OK;
893 }
894
895 static HRESULT WINAPI
896 IDirectDrawSurface7Impl_AddAttachedSurface(IDirectDrawSurface7 *iface,
897                                            IDirectDrawSurface7 *Attach)
898 {
899     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
900     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
901
902     /* Version 7 of this interface seems to refuse everything except z buffers, as per msdn */
903     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
904     {
905
906         WARN("Application tries to attach a non Z buffer surface. caps %08x\n",
907               Surf->surface_desc.ddsCaps.dwCaps);
908         return DDERR_CANNOTATTACHSURFACE;
909     }
910
911     return IDirectDrawSurfaceImpl_AddAttachedSurface(This,
912                                                      Surf);
913 }
914 /*****************************************************************************
915  * IDirectDrawSurface7::DeleteAttachedSurface
916  *
917  * Removes a surface from the attachment chain. The surface's refcount
918  * is decreased by one after it has been removed
919  *
920  * Params:
921  *  Flags: Some flags, not used by this implementation
922  *  Attach: Surface to detach
923  *
924  * Returns:
925  *  DD_OK on success
926  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
927  *
928  *****************************************************************************/
929 static HRESULT WINAPI
930 IDirectDrawSurfaceImpl_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
931                                              DWORD Flags,
932                                              IDirectDrawSurface7 *Attach)
933 {
934     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
935     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Attach);
936     IDirectDrawSurfaceImpl *Prev = This;
937     TRACE("(%p)->(%08x,%p)\n", This, Flags, Surf);
938
939     EnterCriticalSection(&ddraw_cs);
940     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
941     {
942         LeaveCriticalSection(&ddraw_cs);
943         return DDERR_CANNOTDETACHSURFACE;
944     }
945
946     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
947     if (This->surface_desc.ddsCaps.dwCaps &
948         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
949     {
950         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
951         /* FIXME: we should probably also subtract from dwMipMapCount of this
952          * and all parent surfaces */
953     }
954
955     /* Find the predecessor of the detached surface */
956     while(Prev)
957     {
958         if(Prev->next_attached == Surf) break;
959         Prev = Prev->next_attached;
960     }
961
962     /* There must be a surface, otherwise there's a bug */
963     assert(Prev != NULL);
964
965     /* Unchain the surface */
966     Prev->next_attached = Surf->next_attached;
967     Surf->next_attached = NULL;
968     Surf->first_attached = Surf;
969
970     /* Check if the WineD3D depth stencil needs updating */
971     if(This->ddraw->d3ddevice)
972     {
973         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
974     }
975
976     IDirectDrawSurface7_Release(Attach);
977     LeaveCriticalSection(&ddraw_cs);
978     return DD_OK;
979 }
980
981 /*****************************************************************************
982  * IDirectDrawSurface7::AddOverlayDirtyRect
983  *
984  * "This method is not currently implemented"
985  *
986  * Params:
987  *  Rect: ?
988  *
989  * Returns:
990  *  DDERR_UNSUPPORTED
991  *
992  *****************************************************************************/
993 static HRESULT WINAPI
994 IDirectDrawSurfaceImpl_AddOverlayDirtyRect(IDirectDrawSurface7 *iface,
995                                            LPRECT Rect)
996 {
997     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
998     TRACE("(%p)->(%p)\n",This,Rect);
999
1000     /* MSDN says it's not implemented. I could forward it to WineD3D, 
1001      * then we'd implement it, but I don't think that's a good idea
1002      * (Stefan Dösinger)
1003      */
1004 #if 0
1005     return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
1006 #endif
1007     return DDERR_UNSUPPORTED; /* unchecked */
1008 }
1009
1010 /*****************************************************************************
1011  * IDirectDrawSurface7::GetDC
1012  *
1013  * Returns a GDI device context for the surface
1014  *
1015  * Params:
1016  *  hdc: Address of a HDC variable to store the dc to
1017  *
1018  * Returns:
1019  *  DD_OK on success
1020  *  DDERR_INVALIDPARAMS if hdc is NULL
1021  *  For details, see IWineD3DSurface::GetDC
1022  *
1023  *****************************************************************************/
1024 static HRESULT WINAPI
1025 IDirectDrawSurfaceImpl_GetDC(IDirectDrawSurface7 *iface,
1026                              HDC *hdc)
1027 {
1028     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1029     HRESULT hr;
1030     TRACE("(%p)->(%p): Relay\n", This, hdc);
1031
1032     if(!hdc)
1033         return DDERR_INVALIDPARAMS;
1034
1035     EnterCriticalSection(&ddraw_cs);
1036     hr = IWineD3DSurface_GetDC(This->WineD3DSurface,
1037                                hdc);
1038     LeaveCriticalSection(&ddraw_cs);
1039     return hr;
1040 }
1041
1042 /*****************************************************************************
1043  * IDirectDrawSurface7::ReleaseDC
1044  *
1045  * Releases the DC that was constructed with GetDC
1046  *
1047  * Params:
1048  *  hdc: HDC to release
1049  *
1050  * Returns:
1051  *  DD_OK on success
1052  *  For more details, see IWineD3DSurface::ReleaseDC
1053  *
1054  *****************************************************************************/
1055 static HRESULT WINAPI
1056 IDirectDrawSurfaceImpl_ReleaseDC(IDirectDrawSurface7 *iface,
1057                                  HDC hdc)
1058 {
1059     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1060     HRESULT hr;
1061     TRACE("(%p)->(%p): Relay\n", This, hdc);
1062
1063     EnterCriticalSection(&ddraw_cs);
1064     hr = IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
1065     LeaveCriticalSection(&ddraw_cs);
1066     return hr;
1067 }
1068
1069 /*****************************************************************************
1070  * IDirectDrawSurface7::GetCaps
1071  *
1072  * Returns the surface's caps
1073  *
1074  * Params:
1075  *  Caps: Address to write the caps to
1076  *
1077  * Returns:
1078  *  DD_OK on success
1079  *  DDERR_INVALIDPARAMS if Caps is NULL
1080  *
1081  *****************************************************************************/
1082 static HRESULT WINAPI
1083 IDirectDrawSurfaceImpl_GetCaps(IDirectDrawSurface7 *iface,
1084                                DDSCAPS2 *Caps)
1085 {
1086     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1087     TRACE("(%p)->(%p)\n",This,Caps);
1088
1089     if(!Caps)
1090         return DDERR_INVALIDPARAMS;
1091
1092     *Caps = This->surface_desc.ddsCaps;
1093     return DD_OK;
1094 }
1095
1096 /*****************************************************************************
1097  * IDirectDrawSurface7::SetPriority
1098  *
1099  * Sets a texture priority for managed textures.
1100  *
1101  * Params:
1102  *  Priority: The new priority
1103  *
1104  * Returns:
1105  *  DD_OK on success
1106  *  For more details, see IWineD3DSurface::SetPriority
1107  *
1108  *****************************************************************************/
1109 static HRESULT WINAPI
1110 IDirectDrawSurfaceImpl_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1111 {
1112     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1113     HRESULT hr;
1114     TRACE("(%p)->(%d): Relay!\n",This,Priority);
1115
1116     EnterCriticalSection(&ddraw_cs);
1117     hr = IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1118     LeaveCriticalSection(&ddraw_cs);
1119     return hr;
1120 }
1121
1122 /*****************************************************************************
1123  * IDirectDrawSurface7::GetPriority
1124  *
1125  * Returns the surface's priority
1126  *
1127  * Params:
1128  *  Priority: Address of a variable to write the priority to
1129  *
1130  * Returns:
1131  *  D3D_OK on success
1132  *  DDERR_INVALIDPARAMS if Priority == NULL
1133  *  For more details, see IWineD3DSurface::GetPriority
1134  *
1135  *****************************************************************************/
1136 static HRESULT WINAPI
1137 IDirectDrawSurfaceImpl_GetPriority(IDirectDrawSurface7 *iface,
1138                                    DWORD *Priority)
1139 {
1140     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1141     TRACE("(%p)->(%p): Relay\n",This,Priority);
1142
1143     if(!Priority)
1144     {
1145         return DDERR_INVALIDPARAMS;
1146     }
1147
1148     EnterCriticalSection(&ddraw_cs);
1149     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1150     LeaveCriticalSection(&ddraw_cs);
1151     return DD_OK;
1152 }
1153
1154 /*****************************************************************************
1155  * IDirectDrawSurface7::SetPrivateData
1156  *
1157  * Stores some data in the surface that is intended for the application's
1158  * use.
1159  *
1160  * Params:
1161  *  tag: GUID that identifies the data
1162  *  Data: Pointer to the private data
1163  *  Size: Size of the private data
1164  *  Flags: Some flags
1165  *
1166  * Returns:
1167  *  D3D_OK on success
1168  *  For more details, see IWineD3DSurface::SetPrivateData
1169  *
1170  *****************************************************************************/
1171 static HRESULT WINAPI
1172 IDirectDrawSurfaceImpl_SetPrivateData(IDirectDrawSurface7 *iface,
1173                                       REFGUID tag,
1174                                       void *Data,
1175                                       DWORD Size,
1176                                       DWORD Flags)
1177 {
1178     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1179     HRESULT hr;
1180     TRACE("(%p)->(%s,%p,%d,%x): Relay\n", This, debugstr_guid(tag), Data, Size, Flags);
1181
1182     EnterCriticalSection(&ddraw_cs);
1183     hr = IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1184                                         tag,
1185                                         Data,
1186                                         Size,
1187                                         Flags);
1188     LeaveCriticalSection(&ddraw_cs);
1189     switch(hr)
1190     {
1191         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1192         default:                            return hr;
1193     }
1194 }
1195
1196 /*****************************************************************************
1197  * IDirectDrawSurface7::GetPrivateData
1198  *
1199  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1200  *
1201  * Params:
1202  *  tag: GUID of the data to return
1203  *  Data: Address where to write the data to
1204  *  Size: Size of the buffer at Data
1205  *
1206  * Returns:
1207  *  DD_OK on success
1208  *  DDERR_INVALIDPARAMS if Data is NULL
1209  *  For more details, see IWineD3DSurface::GetPrivateData
1210  *
1211  *****************************************************************************/
1212 static HRESULT WINAPI
1213 IDirectDrawSurfaceImpl_GetPrivateData(IDirectDrawSurface7 *iface,
1214                                       REFGUID tag,
1215                                       void *Data,
1216                                       DWORD *Size)
1217 {
1218     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1219     HRESULT hr;
1220     TRACE("(%p)->(%s,%p,%p): Relay\n", This, debugstr_guid(tag), Data, Size);
1221
1222     if(!Data)
1223         return DDERR_INVALIDPARAMS;
1224
1225     EnterCriticalSection(&ddraw_cs);
1226     hr = IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1227                                         tag,
1228                                         Data,
1229                                         Size);
1230     LeaveCriticalSection(&ddraw_cs);
1231     return hr;
1232 }
1233
1234 /*****************************************************************************
1235  * IDirectDrawSurface7::FreePrivateData
1236  *
1237  * Frees private data stored in the surface
1238  *
1239  * Params:
1240  *  tag: Tag of the data to free
1241  *
1242  * Returns:
1243  *  D3D_OK on success
1244  *  For more details, see IWineD3DSurface::FreePrivateData
1245  *
1246  *****************************************************************************/
1247 static HRESULT WINAPI
1248 IDirectDrawSurfaceImpl_FreePrivateData(IDirectDrawSurface7 *iface,
1249                                        REFGUID tag)
1250 {
1251     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1252     HRESULT hr;
1253     TRACE("(%p)->(%s): Relay\n", This, debugstr_guid(tag));
1254
1255     EnterCriticalSection(&ddraw_cs);
1256     hr = IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1257     LeaveCriticalSection(&ddraw_cs);
1258     return hr;
1259 }
1260
1261 /*****************************************************************************
1262  * IDirectDrawSurface7::PageLock
1263  *
1264  * Prevents a sysmem surface from being paged out
1265  *
1266  * Params:
1267  *  Flags: Not used, must be 0(unchecked)
1268  *
1269  * Returns:
1270  *  DD_OK, because it's a stub
1271  *
1272  *****************************************************************************/
1273 static HRESULT WINAPI
1274 IDirectDrawSurfaceImpl_PageLock(IDirectDrawSurface7 *iface,
1275                                 DWORD Flags)
1276 {
1277     TRACE("(%p)->(%x)\n", iface, Flags);
1278
1279     /* This is Windows memory management related - we don't need this */
1280     return DD_OK;
1281 }
1282
1283 /*****************************************************************************
1284  * IDirectDrawSurface7::PageUnlock
1285  *
1286  * Allows a sysmem surface to be paged out
1287  *
1288  * Params:
1289  *  Flags: Not used, must be 0(unckeched)
1290  *
1291  * Returns:
1292  *  DD_OK, because it's a stub
1293  *
1294  *****************************************************************************/
1295 static HRESULT WINAPI
1296 IDirectDrawSurfaceImpl_PageUnlock(IDirectDrawSurface7 *iface,
1297                                   DWORD Flags)
1298 {
1299     TRACE("(%p)->(%x)\n", iface, Flags);
1300
1301     return DD_OK;
1302 }
1303
1304 /*****************************************************************************
1305  * IDirectDrawSurface7::BltBatch
1306  *
1307  * An unimplemented function
1308  *
1309  * Params:
1310  *  ?
1311  *
1312  * Returns:
1313  *  DDERR_UNSUPPORTED
1314  *
1315  *****************************************************************************/
1316 static HRESULT WINAPI IDirectDrawSurfaceImpl_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1317 {
1318     TRACE("(%p)->(%p,%d,%08x)\n",iface,Batch,Count,Flags);
1319
1320     /* MSDN: "not currently implemented" */
1321     return DDERR_UNSUPPORTED;
1322 }
1323
1324 /*****************************************************************************
1325  * IDirectDrawSurface7::EnumAttachedSurfaces
1326  *
1327  * Enumerates all surfaces attached to this surface
1328  *
1329  * Params:
1330  *  context: Pointer to pass unmodified to the callback
1331  *  cb: Callback function to call for each surface
1332  *
1333  * Returns:
1334  *  DD_OK on success
1335  *  DDERR_INVALIDPARAMS if cb is NULL
1336  *
1337  *****************************************************************************/
1338 static HRESULT WINAPI
1339 IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1340                                             void *context,
1341                                             LPDDENUMSURFACESCALLBACK7 cb)
1342 {
1343     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1344     IDirectDrawSurfaceImpl *surf;
1345     DDSURFACEDESC2 desc;
1346     int i;
1347
1348     /* Attached surfaces aren't handled in WineD3D */
1349     TRACE("(%p)->(%p,%p)\n",This,context,cb);
1350
1351     if(!cb)
1352         return DDERR_INVALIDPARAMS;
1353
1354     EnterCriticalSection(&ddraw_cs);
1355     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1356     {
1357         surf = This->complex_array[i];
1358         if(!surf) break;
1359
1360         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1361         desc = surf->surface_desc;
1362         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1363         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1364         {
1365             LeaveCriticalSection(&ddraw_cs);
1366             return DD_OK;
1367         }
1368     }
1369
1370     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1371     {
1372         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
1373         desc = surf->surface_desc;
1374         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1375         if (cb( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
1376         {
1377             LeaveCriticalSection(&ddraw_cs);
1378             return DD_OK;
1379         }
1380     }
1381
1382     TRACE(" end of enumeration.\n");
1383
1384     LeaveCriticalSection(&ddraw_cs);
1385     return DD_OK;
1386 }
1387
1388 /*****************************************************************************
1389  * IDirectDrawSurface7::EnumOverlayZOrders
1390  *
1391  * "Enumerates the overlay surfaces on the specified destination"
1392  *
1393  * Params:
1394  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1395  *  context: context to pass back to the callback
1396  *  cb: callback function to call for each enumerated surface
1397  *
1398  * Returns:
1399  *  DD_OK, because it's a stub
1400  *
1401  *****************************************************************************/
1402 static HRESULT WINAPI
1403 IDirectDrawSurfaceImpl_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1404                                           DWORD Flags,
1405                                           void *context,
1406                                           LPDDENUMSURFACESCALLBACK7 cb)
1407 {
1408      FIXME("(%p)->(%x,%p,%p): Stub!\n", iface, Flags, context, cb);
1409
1410     return DD_OK;
1411 }
1412
1413 /*****************************************************************************
1414  * IDirectDrawSurface7::GetBltStatus
1415  *
1416  * Returns the blitting status
1417  *
1418  * Params:
1419  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1420  *
1421  * Returns:
1422  *  See IWineD3DSurface::Blt
1423  *
1424  *****************************************************************************/
1425 static HRESULT WINAPI
1426 IDirectDrawSurfaceImpl_GetBltStatus(IDirectDrawSurface7 *iface,
1427                                     DWORD Flags)
1428 {
1429     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1430     HRESULT hr;
1431     TRACE("(%p)->(%x): Relay\n", This, Flags);
1432
1433     EnterCriticalSection(&ddraw_cs);
1434     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1435     LeaveCriticalSection(&ddraw_cs);
1436     switch(hr)
1437     {
1438         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1439         default:                            return hr;
1440     }
1441 }
1442
1443 /*****************************************************************************
1444  * IDirectDrawSurface7::GetColorKey
1445  *
1446  * Returns the color key assigned to the surface
1447  *
1448  * Params:
1449  *  Flags: Some flags
1450  *  CKey: Address to store the key to
1451  *
1452  * Returns:
1453  *  DD_OK on success
1454  *  DDERR_INVALIDPARAMS if CKey is NULL
1455  *
1456  *****************************************************************************/
1457 static HRESULT WINAPI
1458 IDirectDrawSurfaceImpl_GetColorKey(IDirectDrawSurface7 *iface,
1459                                    DWORD Flags,
1460                                    DDCOLORKEY *CKey)
1461 {
1462     /* There is a DDERR_NOCOLORKEY error, but how do we know if a color key
1463      * isn't there? That's like saying that an int isn't there. (Which MS
1464      * has done in other docs.) */
1465     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1466     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
1467
1468     if(!CKey)
1469         return DDERR_INVALIDPARAMS;
1470
1471     EnterCriticalSection(&ddraw_cs);
1472     switch (Flags)
1473     {
1474     case DDCKEY_DESTBLT:
1475         *CKey = This->surface_desc.ddckCKDestBlt;
1476         break;
1477
1478     case DDCKEY_DESTOVERLAY:
1479         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1480         break;
1481
1482     case DDCKEY_SRCBLT:
1483         *CKey = This->surface_desc.ddckCKSrcBlt;
1484         break;
1485
1486     case DDCKEY_SRCOVERLAY:
1487         *CKey = This->surface_desc.ddckCKSrcOverlay;
1488         break;
1489
1490     default:
1491         LeaveCriticalSection(&ddraw_cs);
1492         return DDERR_INVALIDPARAMS;
1493     }
1494
1495     LeaveCriticalSection(&ddraw_cs);
1496     return DD_OK;
1497 }
1498
1499 /*****************************************************************************
1500  * IDirectDrawSurface7::GetFlipStatus
1501  *
1502  * Returns the flipping status of the surface
1503  *
1504  * Params:
1505  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1506  *
1507  * Returns:
1508  *  See IWineD3DSurface::GetFlipStatus
1509  *
1510  *****************************************************************************/
1511 static HRESULT WINAPI
1512 IDirectDrawSurfaceImpl_GetFlipStatus(IDirectDrawSurface7 *iface,
1513                                      DWORD Flags)
1514 {
1515     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1516     HRESULT hr;
1517     TRACE("(%p)->(%x): Relay\n", This, Flags);
1518
1519     EnterCriticalSection(&ddraw_cs);
1520     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1521     LeaveCriticalSection(&ddraw_cs);
1522     switch(hr)
1523     {
1524         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1525         default:                            return hr;
1526     }
1527 }
1528
1529 /*****************************************************************************
1530  * IDirectDrawSurface7::GetOverlayPosition
1531  *
1532  * Returns the display coordinates of a visible and active overlay surface
1533  *
1534  * Params:
1535  *  X
1536  *  Y
1537  *
1538  * Returns:
1539  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1540  *****************************************************************************/
1541 static HRESULT WINAPI
1542 IDirectDrawSurfaceImpl_GetOverlayPosition(IDirectDrawSurface7 *iface,
1543                                           LONG *X,
1544                                           LONG *Y) {
1545     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1546     HRESULT hr;
1547     TRACE("(%p)->(%p,%p): Relay\n", This, X, Y);
1548
1549     EnterCriticalSection(&ddraw_cs);
1550     hr = IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1551                                             X,
1552                                             Y);
1553     LeaveCriticalSection(&ddraw_cs);
1554     return hr;
1555 }
1556
1557 /*****************************************************************************
1558  * IDirectDrawSurface7::GetPixelFormat
1559  *
1560  * Returns the pixel format of the Surface
1561  *
1562  * Params:
1563  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1564  *               format should be written
1565  *
1566  * Returns:
1567  *  DD_OK on success
1568  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1569  *
1570  *****************************************************************************/
1571 static HRESULT WINAPI
1572 IDirectDrawSurfaceImpl_GetPixelFormat(IDirectDrawSurface7 *iface,
1573                                       DDPIXELFORMAT *PixelFormat)
1574 {
1575     /* What is DDERR_INVALIDSURFACETYPE for here? */
1576     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1577     TRACE("(%p)->(%p)\n",This,PixelFormat);
1578
1579     if(!PixelFormat)
1580         return DDERR_INVALIDPARAMS;
1581
1582     EnterCriticalSection(&ddraw_cs);
1583     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1584     LeaveCriticalSection(&ddraw_cs);
1585
1586     return DD_OK;
1587 }
1588
1589
1590 /*****************************************************************************
1591  * IDirectDrawSurface7::GetSurfaceDesc
1592  *
1593  * Returns the description of this surface
1594  *
1595  * Params:
1596  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1597  *        surface desc
1598  *
1599  * Returns:
1600  *  DD_OK on success
1601  *  DDERR_INVALIDPARAMS if DDSD is NULL
1602  *
1603  *****************************************************************************/
1604 static HRESULT WINAPI
1605 IDirectDrawSurfaceImpl_GetSurfaceDesc(IDirectDrawSurface7 *iface,
1606                                       DDSURFACEDESC2 *DDSD)
1607 {
1608     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1609
1610     TRACE("(%p)->(%p)\n",This,DDSD);
1611
1612     if(!DDSD)
1613         return DDERR_INVALIDPARAMS;
1614
1615     if (DDSD->dwSize != sizeof(DDSURFACEDESC2))
1616     {
1617         WARN("Incorrect struct size %d, returning DDERR_INVALIDPARAMS\n",DDSD->dwSize);
1618         return DDERR_INVALIDPARAMS;
1619     }
1620
1621     EnterCriticalSection(&ddraw_cs);
1622     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1623     TRACE("Returning surface desc:\n");
1624     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1625
1626     LeaveCriticalSection(&ddraw_cs);
1627     return DD_OK;
1628 }
1629
1630 /*****************************************************************************
1631  * IDirectDrawSurface7::Initialize
1632  *
1633  * Initializes the surface. This is a no-op in Wine
1634  *
1635  * Params:
1636  *  DD: Pointer to an DirectDraw interface
1637  *  DDSD: Surface description for initialization
1638  *
1639  * Returns:
1640  *  DDERR_ALREADYINITIALIZED
1641  *
1642  *****************************************************************************/
1643 static HRESULT WINAPI
1644 IDirectDrawSurfaceImpl_Initialize(IDirectDrawSurface7 *iface,
1645                                   IDirectDraw *DD,
1646                                   DDSURFACEDESC2 *DDSD)
1647 {
1648     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1649     IDirectDrawImpl *ddimpl = ICOM_OBJECT(IDirectDrawImpl, IDirectDraw, DD);
1650     TRACE("(%p)->(%p,%p)\n",This,ddimpl,DDSD);
1651
1652     return DDERR_ALREADYINITIALIZED;
1653 }
1654
1655 /*****************************************************************************
1656  * IDirectDrawSurface7::IsLost
1657  *
1658  * Checks if the surface is lost
1659  *
1660  * Returns:
1661  *  DD_OK, if the surface is useable
1662  *  DDERR_ISLOST if the surface is lost
1663  *  See IWineD3DSurface::IsLost for more details
1664  *
1665  *****************************************************************************/
1666 static HRESULT WINAPI
1667 IDirectDrawSurfaceImpl_IsLost(IDirectDrawSurface7 *iface)
1668 {
1669     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1670     HRESULT hr;
1671     TRACE("(%p)\n", This);
1672
1673     EnterCriticalSection(&ddraw_cs);
1674     /* We lose the surface if the implementation was changed */
1675     if(This->ImplType != This->ddraw->ImplType)
1676     {
1677         /* But this shouldn't happen. When we change the implementation,
1678          * all surfaces are re-created automatically, and their content
1679          * is copied
1680          */
1681         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
1682         LeaveCriticalSection(&ddraw_cs);
1683         return DDERR_SURFACELOST;
1684     }
1685
1686     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
1687     LeaveCriticalSection(&ddraw_cs);
1688     switch(hr)
1689     {
1690         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
1691          * WineD3D uses the same error for surfaces
1692          */
1693         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
1694         default:                            return hr;
1695     }
1696 }
1697
1698 /*****************************************************************************
1699  * IDirectDrawSurface7::Restore
1700  *
1701  * Restores a lost surface. This makes the surface usable again, but
1702  * doesn't reload its old contents
1703  *
1704  * Returns:
1705  *  DD_OK on success
1706  *  See IWineD3DSurface::Restore for more details
1707  *
1708  *****************************************************************************/
1709 static HRESULT WINAPI
1710 IDirectDrawSurfaceImpl_Restore(IDirectDrawSurface7 *iface)
1711 {
1712     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1713     HRESULT hr;
1714     TRACE("(%p)\n", This);
1715
1716     EnterCriticalSection(&ddraw_cs);
1717     if(This->ImplType != This->ddraw->ImplType)
1718     {
1719         /* Call the recreation callback. Make sure to AddRef first */
1720         IDirectDrawSurface_AddRef(iface);
1721         IDirectDrawImpl_RecreateSurfacesCallback(iface,
1722                                                  &This->surface_desc,
1723                                                  NULL /* Not needed */);
1724     }
1725     hr = IWineD3DSurface_Restore(This->WineD3DSurface);
1726     LeaveCriticalSection(&ddraw_cs);
1727     return hr;
1728 }
1729
1730 /*****************************************************************************
1731  * IDirectDrawSurface7::SetOverlayPosition
1732  *
1733  * Changes the display coordinates of an overlay surface
1734  *
1735  * Params:
1736  *  X:
1737  *  Y:
1738  *
1739  * Returns:
1740  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
1741  *****************************************************************************/
1742 static HRESULT WINAPI
1743 IDirectDrawSurfaceImpl_SetOverlayPosition(IDirectDrawSurface7 *iface,
1744                                           LONG X,
1745                                           LONG Y)
1746 {
1747     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1748     HRESULT hr;
1749     TRACE("(%p)->(%d,%d): Relay\n", This, X, Y);
1750
1751     EnterCriticalSection(&ddraw_cs);
1752     hr = IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
1753                                             X,
1754                                             Y);
1755     LeaveCriticalSection(&ddraw_cs);
1756     return hr;
1757 }
1758
1759 /*****************************************************************************
1760  * IDirectDrawSurface7::UpdateOverlay
1761  *
1762  * Modifies the attributes of an overlay surface.
1763  *
1764  * Params:
1765  *  SrcRect: The section of the source being used for the overlay
1766  *  DstSurface: Address of the surface that is overlaid
1767  *  DstRect: Place of the overlay
1768  *  Flags: some DDOVER_* flags
1769  *
1770  * Returns:
1771  *  DDERR_UNSUPPORTED, because we don't support overlays
1772  *
1773  *****************************************************************************/
1774 static HRESULT WINAPI
1775 IDirectDrawSurfaceImpl_UpdateOverlay(IDirectDrawSurface7 *iface,
1776                                      LPRECT SrcRect,
1777                                      IDirectDrawSurface7 *DstSurface,
1778                                      LPRECT DstRect,
1779                                      DWORD Flags,
1780                                      LPDDOVERLAYFX FX)
1781 {
1782     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1783     IDirectDrawSurfaceImpl *Dst = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DstSurface);
1784     HRESULT hr;
1785     TRACE("(%p)->(%p,%p,%p,%x,%p): Relay\n", This, SrcRect, Dst, DstRect, Flags, FX);
1786
1787     EnterCriticalSection(&ddraw_cs);
1788     hr = IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
1789                                        SrcRect,
1790                                        Dst ? Dst->WineD3DSurface : NULL,
1791                                        DstRect,
1792                                        Flags,
1793                                        (WINEDDOVERLAYFX *) FX);
1794     LeaveCriticalSection(&ddraw_cs);
1795     return hr;
1796 }
1797
1798 /*****************************************************************************
1799  * IDirectDrawSurface7::UpdateOverlayDisplay
1800  *
1801  * The DX7 sdk says that it's not implemented
1802  *
1803  * Params:
1804  *  Flags: ?
1805  *
1806  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
1807  *
1808  *****************************************************************************/
1809 static HRESULT WINAPI
1810 IDirectDrawSurfaceImpl_UpdateOverlayDisplay(IDirectDrawSurface7 *iface,
1811                                             DWORD Flags)
1812 {
1813     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1814     TRACE("(%p)->(%x)\n", This, Flags);
1815     return DDERR_UNSUPPORTED;
1816 }
1817
1818 /*****************************************************************************
1819  * IDirectDrawSurface7::UpdateOverlayZOrder
1820  *
1821  * Sets an overlay's Z order
1822  *
1823  * Params:
1824  *  Flags: DDOVERZ_* flags
1825  *  DDSRef: Defines the relative position in the overlay chain
1826  *
1827  * Returns:
1828  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
1829  *
1830  *****************************************************************************/
1831 static HRESULT WINAPI
1832 IDirectDrawSurfaceImpl_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
1833                                            DWORD Flags,
1834                                            IDirectDrawSurface7 *DDSRef)
1835 {
1836     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1837     HRESULT hr;
1838     IDirectDrawSurfaceImpl *Ref = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DDSRef);
1839
1840     TRACE("(%p)->(%x,%p): Relay\n", This, Flags, Ref);
1841     EnterCriticalSection(&ddraw_cs);
1842     hr =  IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
1843                                               Flags,
1844                                               Ref ? Ref->WineD3DSurface : NULL);
1845     LeaveCriticalSection(&ddraw_cs);
1846     return hr;
1847 }
1848
1849 /*****************************************************************************
1850  * IDirectDrawSurface7::GetDDInterface
1851  *
1852  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
1853  * surface belongs to
1854  *
1855  * Params:
1856  *  DD: Address to write the interface pointer to
1857  *
1858  * Returns:
1859  *  DD_OK on success
1860  *  DDERR_INVALIDPARAMS if DD is NULL
1861  *
1862  *****************************************************************************/
1863 static HRESULT WINAPI
1864 IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
1865                                       void **DD)
1866 {
1867     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1868
1869     TRACE("(%p)->(%p)\n",This,DD);
1870
1871     if(!DD)
1872         return DDERR_INVALIDPARAMS;
1873
1874     switch(This->version)
1875     {
1876         case 7:
1877             *((IDirectDraw7 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw7);
1878             IDirectDraw7_AddRef(*(IDirectDraw7 **) DD);
1879             break;
1880
1881         case 4:
1882             *((IDirectDraw4 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw4);
1883             IDirectDraw4_AddRef(*(IDirectDraw4 **) DD);
1884             break;
1885
1886         case 2:
1887             *((IDirectDraw2 **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw2);
1888             IDirectDraw_AddRef( *(IDirectDraw2 **) DD);
1889             break;
1890
1891         case 1:
1892             *((IDirectDraw **) DD) = ICOM_INTERFACE(This->ddraw, IDirectDraw);
1893             IDirectDraw_AddRef( *(IDirectDraw **) DD);
1894             break;
1895
1896     }
1897
1898     return DD_OK;
1899 }
1900
1901 /* This seems also windows implementation specific - I don't think WineD3D needs this */
1902 static HRESULT WINAPI IDirectDrawSurfaceImpl_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
1903 {
1904     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1905     volatile IDirectDrawSurfaceImpl* vThis = This;
1906
1907     TRACE("(%p)\n",This);
1908     EnterCriticalSection(&ddraw_cs);
1909     /* A uniqueness value of 0 is apparently special.
1910      * This needs to be checked.
1911      * TODO: Write tests for this code and check if the volatile, interlocked stuff is really needed
1912      */
1913     while (1) {
1914         DWORD old_uniqueness_value = vThis->uniqueness_value;
1915         DWORD new_uniqueness_value = old_uniqueness_value+1;
1916
1917         if (old_uniqueness_value == 0) break;
1918         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
1919
1920         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
1921                                       old_uniqueness_value,
1922                                       new_uniqueness_value)
1923             == old_uniqueness_value)
1924             break;
1925     }
1926
1927     LeaveCriticalSection(&ddraw_cs);
1928     return DD_OK;
1929 }
1930
1931 static HRESULT WINAPI IDirectDrawSurfaceImpl_GetUniquenessValue(IDirectDrawSurface7 *iface, LPDWORD pValue)
1932 {
1933     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1934
1935     TRACE("(%p)->(%p)\n",This,pValue);
1936     EnterCriticalSection(&ddraw_cs);
1937     *pValue = This->uniqueness_value;
1938     LeaveCriticalSection(&ddraw_cs);
1939     return DD_OK;
1940 }
1941
1942 /*****************************************************************************
1943  * IDirectDrawSurface7::SetLOD
1944  *
1945  * Sets the level of detail of a texture
1946  *
1947  * Params:
1948  *  MaxLOD: LOD to set
1949  *
1950  * Returns:
1951  *  DD_OK on success
1952  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1953  *
1954  *****************************************************************************/
1955 static HRESULT WINAPI
1956 IDirectDrawSurfaceImpl_SetLOD(IDirectDrawSurface7 *iface,
1957                               DWORD MaxLOD)
1958 {
1959     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
1960     HRESULT hr;
1961     TRACE("(%p)->(%d)\n", This, MaxLOD);
1962
1963     EnterCriticalSection(&ddraw_cs);
1964     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1965     {
1966         LeaveCriticalSection(&ddraw_cs);
1967         return DDERR_INVALIDOBJECT;
1968     }
1969
1970     if(!This->wineD3DTexture)
1971     {
1972         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
1973         LeaveCriticalSection(&ddraw_cs);
1974         return DDERR_INVALIDOBJECT;
1975     }
1976
1977     hr = IWineD3DBaseTexture_SetLOD(This->wineD3DTexture,
1978                                     MaxLOD);
1979     LeaveCriticalSection(&ddraw_cs);
1980     return hr;
1981 }
1982
1983 /*****************************************************************************
1984  * IDirectDrawSurface7::GetLOD
1985  *
1986  * Returns the level of detail of a Direct3D texture
1987  *
1988  * Params:
1989  *  MaxLOD: Address to write the LOD to
1990  *
1991  * Returns:
1992  *  DD_OK on success
1993  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
1994  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1995  *
1996  *****************************************************************************/
1997 static HRESULT WINAPI
1998 IDirectDrawSurfaceImpl_GetLOD(IDirectDrawSurface7 *iface,
1999                               DWORD *MaxLOD)
2000 {
2001     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2002     TRACE("(%p)->(%p)\n", This, MaxLOD);
2003
2004     if(!MaxLOD)
2005         return DDERR_INVALIDPARAMS;
2006
2007     EnterCriticalSection(&ddraw_cs);
2008     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2009     {
2010         LeaveCriticalSection(&ddraw_cs);
2011         return DDERR_INVALIDOBJECT;
2012     }
2013
2014     *MaxLOD = IWineD3DBaseTexture_GetLOD(This->wineD3DTexture);
2015     LeaveCriticalSection(&ddraw_cs);
2016     return DD_OK;
2017 }
2018
2019 /*****************************************************************************
2020  * IDirectDrawSurface7::BltFast
2021  *
2022  * Performs a fast Blit.
2023  *
2024  * Params:
2025  *  dstx: The x coordinate to blit to on the destination
2026  *  dsty: The y coordinate to blit to on the destination
2027  *  Source: The source surface
2028  *  rsrc: The source rectangle
2029  *  trans: Type of transfer. Some DDBLTFAST_* flags
2030  *
2031  * Returns:
2032  *  DD_OK on success
2033  *  For more details, see IWineD3DSurface::BltFast
2034  *
2035  *****************************************************************************/
2036 static HRESULT WINAPI
2037 IDirectDrawSurfaceImpl_BltFast(IDirectDrawSurface7 *iface,
2038                                DWORD dstx,
2039                                DWORD dsty,
2040                                IDirectDrawSurface7 *Source,
2041                                RECT *rsrc,
2042                                DWORD trans)
2043 {
2044     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2045     HRESULT hr;
2046     IDirectDrawSurfaceImpl *src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Source);
2047     TRACE("(%p)->(%d,%d,%p,%p,%d): Relay\n", This, dstx, dsty, Source, rsrc, trans);
2048
2049     /* Source must be != NULL, This is not checked by windows. Windows happily throws a 0xc0000005
2050      * in that case
2051      */
2052     if(rsrc)
2053     {
2054         if(rsrc->top > rsrc->bottom || rsrc->left > rsrc->right ||
2055            rsrc->right > src->surface_desc.dwWidth ||
2056            rsrc->bottom > src->surface_desc.dwHeight)
2057         {
2058             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
2059             return DDERR_INVALIDRECT;
2060         }
2061         if(dstx + rsrc->right - rsrc->left > This->surface_desc.dwWidth ||
2062            dsty + rsrc->bottom - rsrc->top > This->surface_desc.dwHeight)
2063         {
2064             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2065             return DDERR_INVALIDRECT;
2066         }
2067     }
2068     else
2069     {
2070         if(dstx + src->surface_desc.dwWidth > This->surface_desc.dwWidth ||
2071            dsty + src->surface_desc.dwHeight > This->surface_desc.dwHeight)
2072         {
2073             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2074             return DDERR_INVALIDRECT;
2075         }
2076     }
2077
2078     EnterCriticalSection(&ddraw_cs);
2079     hr = IWineD3DSurface_BltFast(This->WineD3DSurface,
2080                                  dstx, dsty,
2081                                  src ? src->WineD3DSurface : NULL,
2082                                  rsrc,
2083                                  trans);
2084     LeaveCriticalSection(&ddraw_cs);
2085     switch(hr)
2086     {
2087         case WINED3DERR_NOTAVAILABLE:           return DDERR_UNSUPPORTED;
2088         case WINED3DERR_WRONGTEXTUREFORMAT:     return DDERR_INVALIDPIXELFORMAT;
2089         default:                                return hr;
2090     }
2091 }
2092
2093 /*****************************************************************************
2094  * IDirectDrawSurface7::GetClipper
2095  *
2096  * Returns the IDirectDrawClipper interface of the clipper assigned to this
2097  * surface
2098  *
2099  * Params:
2100  *  Clipper: Address to store the interface pointer at
2101  *
2102  * Returns:
2103  *  DD_OK on success
2104  *  DDERR_INVALIDPARAMS if Clipper is NULL
2105  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
2106  *
2107  *****************************************************************************/
2108 static HRESULT WINAPI
2109 IDirectDrawSurfaceImpl_GetClipper(IDirectDrawSurface7 *iface,
2110                                   IDirectDrawClipper **Clipper)
2111 {
2112     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2113     TRACE("(%p)->(%p)\n", This, Clipper);
2114
2115     if(!Clipper)
2116     {
2117         LeaveCriticalSection(&ddraw_cs);
2118         return DDERR_INVALIDPARAMS;
2119     }
2120
2121     EnterCriticalSection(&ddraw_cs);
2122     if(This->clipper == NULL)
2123     {
2124         LeaveCriticalSection(&ddraw_cs);
2125         return DDERR_NOCLIPPERATTACHED;
2126     }
2127
2128     *Clipper = ICOM_INTERFACE(This->clipper, IDirectDrawClipper);
2129     IDirectDrawClipper_AddRef(*Clipper);
2130     LeaveCriticalSection(&ddraw_cs);
2131     return DD_OK;
2132 }
2133
2134 /*****************************************************************************
2135  * IDirectDrawSurface7::SetClipper
2136  *
2137  * Sets a clipper for the surface
2138  *
2139  * Params:
2140  *  Clipper: IDirectDrawClipper interface of the clipper to set
2141  *
2142  * Returns:
2143  *  DD_OK on success
2144  *
2145  *****************************************************************************/
2146 static HRESULT WINAPI
2147 IDirectDrawSurfaceImpl_SetClipper(IDirectDrawSurface7 *iface,
2148                                   IDirectDrawClipper *Clipper)
2149 {
2150     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2151     IDirectDrawClipperImpl *oldClipper = This->clipper;
2152     HRESULT hr;
2153     TRACE("(%p)->(%p)\n",This,Clipper);
2154
2155     EnterCriticalSection(&ddraw_cs);
2156     if (ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper) == This->clipper)
2157     {
2158         LeaveCriticalSection(&ddraw_cs);
2159         return DD_OK;
2160     }
2161
2162     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper);
2163
2164     if (Clipper != NULL)
2165         IDirectDrawClipper_AddRef(Clipper);
2166     if(oldClipper)
2167         IDirectDrawClipper_Release(ICOM_INTERFACE(oldClipper, IDirectDrawClipper));
2168
2169     hr = IWineD3DSurface_SetClipper(This->WineD3DSurface, This->clipper ? This->clipper->wineD3DClipper : NULL);
2170     LeaveCriticalSection(&ddraw_cs);
2171     return hr;
2172 }
2173
2174 /*****************************************************************************
2175  * IDirectDrawSurface7::SetSurfaceDesc
2176  *
2177  * Sets the surface description. It can override the pixel format, the surface
2178  * memory, ...
2179  * It's not really tested.
2180  *
2181  * Params:
2182  * DDSD: Pointer to the new surface description to set
2183  * Flags: Some flags
2184  *
2185  * Returns:
2186  *  DD_OK on success
2187  *  DDERR_INVALIDPARAMS if DDSD is NULL
2188  *
2189  *****************************************************************************/
2190 static HRESULT WINAPI
2191 IDirectDrawSurfaceImpl_SetSurfaceDesc(IDirectDrawSurface7 *iface,
2192                                       DDSURFACEDESC2 *DDSD,
2193                                       DWORD Flags)
2194 {
2195     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2196     WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
2197     HRESULT hr;
2198     TRACE("(%p)->(%p,%x)\n", This, DDSD, Flags);
2199
2200     if(!DDSD)
2201         return DDERR_INVALIDPARAMS;
2202
2203     EnterCriticalSection(&ddraw_cs);
2204     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
2205     {
2206         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
2207
2208         if(newFormat == WINED3DFMT_UNKNOWN)
2209         {
2210             ERR("Requested to set an unknown pixelformat\n");
2211             LeaveCriticalSection(&ddraw_cs);
2212             return DDERR_INVALIDPARAMS;
2213         }
2214         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
2215         {
2216             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
2217                                            newFormat);
2218             if(hr != DD_OK)
2219             {
2220                 LeaveCriticalSection(&ddraw_cs);
2221                 return hr;
2222             }
2223         }
2224     }
2225     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
2226     {
2227         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2228                                     DDCKEY_DESTOVERLAY,
2229                                     (WINEDDCOLORKEY *) &DDSD->u3.ddckCKDestOverlay);
2230     }
2231     if (DDSD->dwFlags & DDSD_CKDESTBLT)
2232     {
2233         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2234                                     DDCKEY_DESTBLT,
2235                                     (WINEDDCOLORKEY *) &DDSD->ddckCKDestBlt);
2236     }
2237     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
2238     {
2239         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2240                                     DDCKEY_SRCOVERLAY,
2241                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcOverlay);
2242     }
2243     if (DDSD->dwFlags & DDSD_CKSRCBLT)
2244     {
2245         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2246                                     DDCKEY_SRCBLT,
2247                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcBlt);
2248     }
2249     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
2250     {
2251         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
2252         if(hr != WINED3D_OK)
2253         {
2254             /* No need for a trace here, wined3d does that for us */
2255             LeaveCriticalSection(&ddraw_cs);
2256             switch(hr)
2257             {
2258                 case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2259                 default:                            break; /* Go on */
2260             }
2261         }
2262
2263     }
2264
2265     This->surface_desc = *DDSD;
2266
2267     LeaveCriticalSection(&ddraw_cs);
2268     return DD_OK;
2269 }
2270
2271 /*****************************************************************************
2272  * IDirectDrawSurface7::GetPalette
2273  *
2274  * Returns the IDirectDrawPalette interface of the palette currently assigned
2275  * to the surface
2276  *
2277  * Params:
2278  *  Pal: Address to write the interface pointer to
2279  *
2280  * Returns:
2281  *  DD_OK on success
2282  *  DDERR_INVALIDPARAMS if Pal is NULL
2283  *
2284  *****************************************************************************/
2285 static HRESULT WINAPI
2286 IDirectDrawSurfaceImpl_GetPalette(IDirectDrawSurface7 *iface,
2287                                   IDirectDrawPalette **Pal)
2288 {
2289     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2290     IWineD3DPalette *wPal;
2291     HRESULT hr;
2292     TRACE("(%p)->(%p): Relay\n", This, Pal);
2293
2294     if(!Pal)
2295         return DDERR_INVALIDPARAMS;
2296
2297     EnterCriticalSection(&ddraw_cs);
2298     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
2299     if(hr != DD_OK)
2300     {
2301         LeaveCriticalSection(&ddraw_cs);
2302         return hr;
2303     }
2304
2305     if(wPal)
2306     {
2307         hr = IWineD3DPalette_GetParent(wPal, (IUnknown **) Pal);
2308     }
2309     else
2310     {
2311         *Pal = NULL;
2312         hr = DDERR_NOPALETTEATTACHED;
2313     }
2314
2315     LeaveCriticalSection(&ddraw_cs);
2316     return hr;
2317 }
2318
2319 /*****************************************************************************
2320  * SetColorKeyEnum
2321  *
2322  * EnumAttachedSurface callback for SetColorKey. Used to set color keys
2323  * recursively in the surface tree
2324  *
2325  *****************************************************************************/
2326 struct SCKContext
2327 {
2328     HRESULT ret;
2329     WINEDDCOLORKEY *CKey;
2330     DWORD Flags;
2331 };
2332
2333 static HRESULT WINAPI
2334 SetColorKeyEnum(IDirectDrawSurface7 *surface,
2335                 DDSURFACEDESC2 *desc,
2336                 void *context)
2337 {
2338     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, surface);
2339     struct SCKContext *ctx = context;
2340     HRESULT hr;
2341
2342     hr = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2343                                      ctx->Flags,
2344                                      ctx->CKey);
2345     if(hr != DD_OK)
2346     {
2347         WARN("IWineD3DSurface_SetColorKey failed, hr = %08x\n", hr);
2348         ctx->ret = hr;
2349     }
2350
2351     IDirectDrawSurface7_EnumAttachedSurfaces(surface,
2352                                              context,
2353                                              SetColorKeyEnum);
2354     IDirectDrawSurface7_Release(surface);
2355     return DDENUMRET_OK;
2356 }
2357
2358 /*****************************************************************************
2359  * IDirectDrawSurface7::SetColorKey
2360  *
2361  * Sets the color keying options for the surface. Observations showed that
2362  * in case of complex surfaces the color key has to be assigned to all
2363  * sublevels.
2364  *
2365  * Params:
2366  *  Flags: DDCKEY_*
2367  *  CKey: The new color key
2368  *
2369  * Returns:
2370  *  DD_OK on success
2371  *  See IWineD3DSurface::SetColorKey for details
2372  *
2373  *****************************************************************************/
2374 static HRESULT WINAPI
2375 IDirectDrawSurfaceImpl_SetColorKey(IDirectDrawSurface7 *iface,
2376                                    DWORD Flags,
2377                                    DDCOLORKEY *CKey)
2378 {
2379     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2380     struct SCKContext ctx = { DD_OK, (WINEDDCOLORKEY *) CKey, Flags };
2381     TRACE("(%p)->(%x,%p)\n", This, Flags, CKey);
2382
2383     EnterCriticalSection(&ddraw_cs);
2384     if (CKey)
2385     {
2386         switch (Flags & ~DDCKEY_COLORSPACE)
2387         {
2388         case DDCKEY_DESTBLT:
2389             This->surface_desc.ddckCKDestBlt = *CKey;
2390             This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
2391             break;
2392
2393         case DDCKEY_DESTOVERLAY:
2394             This->surface_desc.u3.ddckCKDestOverlay = *CKey;
2395             This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
2396             break;
2397
2398         case DDCKEY_SRCOVERLAY:
2399             This->surface_desc.ddckCKSrcOverlay = *CKey;
2400             This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
2401             break;
2402
2403         case DDCKEY_SRCBLT:
2404             This->surface_desc.ddckCKSrcBlt = *CKey;
2405             This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
2406             break;
2407
2408         default:
2409             LeaveCriticalSection(&ddraw_cs);
2410             return DDERR_INVALIDPARAMS;
2411         }
2412     }
2413     else
2414     {
2415         switch (Flags & ~DDCKEY_COLORSPACE)
2416         {
2417         case DDCKEY_DESTBLT:
2418             This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
2419             break;
2420
2421         case DDCKEY_DESTOVERLAY:
2422             This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
2423             break;
2424
2425         case DDCKEY_SRCOVERLAY:
2426             This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
2427             break;
2428
2429         case DDCKEY_SRCBLT:
2430             This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
2431             break;
2432
2433         default:
2434             LeaveCriticalSection(&ddraw_cs);
2435             return DDERR_INVALIDPARAMS;
2436         }
2437     }
2438     ctx.ret = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2439                                           Flags,
2440                                           ctx.CKey);
2441     IDirectDrawSurface7_EnumAttachedSurfaces(iface,
2442                                              (void *) &ctx,
2443                                              SetColorKeyEnum);
2444     LeaveCriticalSection(&ddraw_cs);
2445     switch(ctx.ret)
2446     {
2447         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2448         default:                            return ctx.ret;
2449     }
2450 }
2451
2452 /*****************************************************************************
2453  * IDirectDrawSurface7::SetPalette
2454  *
2455  * Assigns a DirectDrawPalette object to the surface
2456  *
2457  * Params:
2458  *  Pal: Interface to the palette to set
2459  *
2460  * Returns:
2461  *  DD_OK on success
2462  *
2463  *****************************************************************************/
2464 static HRESULT WINAPI
2465 IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
2466                                   IDirectDrawPalette *Pal)
2467 {
2468     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
2469     IDirectDrawPalette *oldPal;
2470     IDirectDrawSurfaceImpl *surf;
2471     IDirectDrawPaletteImpl *PalImpl = ICOM_OBJECT(IDirectDrawPaletteImpl, IDirectDrawPalette, Pal);
2472     HRESULT hr;
2473     TRACE("(%p)->(%p)\n", This, Pal);
2474
2475     /* Find the old palette */
2476     EnterCriticalSection(&ddraw_cs);
2477     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2478     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED)
2479     {
2480         LeaveCriticalSection(&ddraw_cs);
2481         return hr;
2482     }
2483     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2484
2485     /* Set the new Palette */
2486     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2487                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2488     /* AddRef the Palette */
2489     if(Pal) IDirectDrawPalette_AddRef(Pal);
2490
2491     /* Release the old palette */
2492     if(oldPal) IDirectDrawPalette_Release(oldPal);
2493
2494     /* If this is a front buffer, also update the back buffers
2495      * TODO: How do things work for palettized cube textures?
2496      */
2497     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2498     {
2499         /* For primary surfaces the tree is just a list, so the simpler scheme fits too */
2500         DDSCAPS2 caps2 = { DDSCAPS_PRIMARYSURFACE, 0, 0, 0 };
2501
2502         surf = This;
2503         while(1)
2504         {
2505             IDirectDrawSurface7 *attach;
2506             HRESULT hr;
2507             hr = IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(surf, IDirectDrawSurface7),
2508                                                         &caps2, &attach);
2509             if(hr != DD_OK)
2510             {
2511                 break;
2512             }
2513
2514             TRACE("Setting palette on %p\n", attach);
2515             IDirectDrawSurface7_SetPalette(attach,
2516                                            Pal);
2517             surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach);
2518             IDirectDrawSurface7_Release(attach);
2519         }
2520     }
2521
2522     LeaveCriticalSection(&ddraw_cs);
2523     return DD_OK;
2524 }
2525
2526 /*****************************************************************************
2527  * The VTable
2528  *****************************************************************************/
2529
2530 const IDirectDrawSurface7Vtbl IDirectDrawSurface7_Vtbl =
2531 {
2532     /*** IUnknown ***/
2533     IDirectDrawSurfaceImpl_QueryInterface,
2534     IDirectDrawSurfaceImpl_AddRef,
2535     IDirectDrawSurfaceImpl_Release,
2536     /*** IDirectDrawSurface ***/
2537     IDirectDrawSurface7Impl_AddAttachedSurface,
2538     IDirectDrawSurfaceImpl_AddOverlayDirtyRect,
2539     IDirectDrawSurfaceImpl_Blt,
2540     IDirectDrawSurfaceImpl_BltBatch,
2541     IDirectDrawSurfaceImpl_BltFast,
2542     IDirectDrawSurfaceImpl_DeleteAttachedSurface,
2543     IDirectDrawSurfaceImpl_EnumAttachedSurfaces,
2544     IDirectDrawSurfaceImpl_EnumOverlayZOrders,
2545     IDirectDrawSurfaceImpl_Flip,
2546     IDirectDrawSurfaceImpl_GetAttachedSurface,
2547     IDirectDrawSurfaceImpl_GetBltStatus,
2548     IDirectDrawSurfaceImpl_GetCaps,
2549     IDirectDrawSurfaceImpl_GetClipper,
2550     IDirectDrawSurfaceImpl_GetColorKey,
2551     IDirectDrawSurfaceImpl_GetDC,
2552     IDirectDrawSurfaceImpl_GetFlipStatus,
2553     IDirectDrawSurfaceImpl_GetOverlayPosition,
2554     IDirectDrawSurfaceImpl_GetPalette,
2555     IDirectDrawSurfaceImpl_GetPixelFormat,
2556     IDirectDrawSurfaceImpl_GetSurfaceDesc,
2557     IDirectDrawSurfaceImpl_Initialize,
2558     IDirectDrawSurfaceImpl_IsLost,
2559     IDirectDrawSurfaceImpl_Lock,
2560     IDirectDrawSurfaceImpl_ReleaseDC,
2561     IDirectDrawSurfaceImpl_Restore,
2562     IDirectDrawSurfaceImpl_SetClipper,
2563     IDirectDrawSurfaceImpl_SetColorKey,
2564     IDirectDrawSurfaceImpl_SetOverlayPosition,
2565     IDirectDrawSurfaceImpl_SetPalette,
2566     IDirectDrawSurfaceImpl_Unlock,
2567     IDirectDrawSurfaceImpl_UpdateOverlay,
2568     IDirectDrawSurfaceImpl_UpdateOverlayDisplay,
2569     IDirectDrawSurfaceImpl_UpdateOverlayZOrder,
2570     /*** IDirectDrawSurface2 ***/
2571     IDirectDrawSurfaceImpl_GetDDInterface,
2572     IDirectDrawSurfaceImpl_PageLock,
2573     IDirectDrawSurfaceImpl_PageUnlock,
2574     /*** IDirectDrawSurface3 ***/
2575     IDirectDrawSurfaceImpl_SetSurfaceDesc,
2576     /*** IDirectDrawSurface4 ***/
2577     IDirectDrawSurfaceImpl_SetPrivateData,
2578     IDirectDrawSurfaceImpl_GetPrivateData,
2579     IDirectDrawSurfaceImpl_FreePrivateData,
2580     IDirectDrawSurfaceImpl_GetUniquenessValue,
2581     IDirectDrawSurfaceImpl_ChangeUniquenessValue,
2582     /*** IDirectDrawSurface7 ***/
2583     IDirectDrawSurfaceImpl_SetPriority,
2584     IDirectDrawSurfaceImpl_GetPriority,
2585     IDirectDrawSurfaceImpl_SetLOD,
2586     IDirectDrawSurfaceImpl_GetLOD
2587 };