1 /*
2  * Copyright 2010 Vincent Povirk for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <stdarg.h>
20 
21 #define COBJMACROS
22 
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
26 
27 #include "wincodecs_private.h"
28 
29 #include "wine/debug.h"
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
32 
33 typedef struct FlipRotator {
34     IWICBitmapFlipRotator IWICBitmapFlipRotator_iface;
35     LONG ref;
36     IWICBitmapSource *source;
37     int flip_x;
38     int flip_y;
39     int swap_xy;
40     CRITICAL_SECTION lock; /* must be held when initialized */
41 } FlipRotator;
42 
43 static inline FlipRotator *impl_from_IWICBitmapFlipRotator(IWICBitmapFlipRotator *iface)
44 {
45     return CONTAINING_RECORD(iface, FlipRotator, IWICBitmapFlipRotator_iface);
46 }
47 
48 static HRESULT WINAPI FlipRotator_QueryInterface(IWICBitmapFlipRotator *iface, REFIID iid,
49     void **ppv)
50 {
51     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
52     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
53 
54     if (!ppv) return E_INVALIDARG;
55 
56     if (IsEqualIID(&IID_IUnknown, iid) ||
57         IsEqualIID(&IID_IWICBitmapSource, iid) ||
58         IsEqualIID(&IID_IWICBitmapFlipRotator, iid))
59     {
60         *ppv = &This->IWICBitmapFlipRotator_iface;
61     }
62     else
63     {
64         *ppv = NULL;
65         return E_NOINTERFACE;
66     }
67 
68     IUnknown_AddRef((IUnknown*)*ppv);
69     return S_OK;
70 }
71 
72 static ULONG WINAPI FlipRotator_AddRef(IWICBitmapFlipRotator *iface)
73 {
74     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
75     ULONG ref = InterlockedIncrement(&This->ref);
76 
77     TRACE("(%p) refcount=%lu\n", iface, ref);
78 
79     return ref;
80 }
81 
82 static ULONG WINAPI FlipRotator_Release(IWICBitmapFlipRotator *iface)
83 {
84     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
85     ULONG ref = InterlockedDecrement(&This->ref);
86 
87     TRACE("(%p) refcount=%lu\n", iface, ref);
88 
89     if (ref == 0)
90     {
91         This->lock.DebugInfo->Spare[0] = 0;
92         DeleteCriticalSection(&This->lock);
93         if (This->source) IWICBitmapSource_Release(This->source);
94         free(This);
95     }
96 
97     return ref;
98 }
99 
100 static HRESULT WINAPI FlipRotator_GetSize(IWICBitmapFlipRotator *iface,
101     UINT *puiWidth, UINT *puiHeight)
102 {
103     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
104     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
105 
106     if (!This->source)
107         return WINCODEC_ERR_WRONGSTATE;
108     else if (This->swap_xy)
109         return IWICBitmapSource_GetSize(This->source, puiHeight, puiWidth);
110     else
111         return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
112 }
113 
114 static HRESULT WINAPI FlipRotator_GetPixelFormat(IWICBitmapFlipRotator *iface,
115     WICPixelFormatGUID *pPixelFormat)
116 {
117     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
118     TRACE("(%p,%p)\n", iface, pPixelFormat);
119 
120     if (!This->source)
121         return WINCODEC_ERR_WRONGSTATE;
122     else
123         return IWICBitmapSource_GetPixelFormat(This->source, pPixelFormat);
124 }
125 
126 static HRESULT WINAPI FlipRotator_GetResolution(IWICBitmapFlipRotator *iface,
127     double *pDpiX, double *pDpiY)
128 {
129     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
130     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
131 
132     if (!This->source)
133         return WINCODEC_ERR_WRONGSTATE;
134     else if (This->swap_xy)
135         return IWICBitmapSource_GetResolution(This->source, pDpiY, pDpiX);
136     else
137         return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
138 }
139 
140 static HRESULT WINAPI FlipRotator_CopyPalette(IWICBitmapFlipRotator *iface,
141     IWICPalette *pIPalette)
142 {
143     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
144     TRACE("(%p,%p)\n", iface, pIPalette);
145 
146     if (!This->source)
147         return WINCODEC_ERR_WRONGSTATE;
148     else
149         return IWICBitmapSource_CopyPalette(This->source, pIPalette);
150 }
151 
152 static HRESULT WINAPI FlipRotator_CopyPixels(IWICBitmapFlipRotator *iface,
153     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
154 {
155     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
156     HRESULT hr;
157     UINT y;
158     UINT srcy, srcwidth, srcheight;
159     WICRect rc;
160     WICRect rect;
161 
162     TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
163 
164     if (!This->source) return WINCODEC_ERR_WRONGSTATE;
165 
166     if (This->swap_xy || This->flip_x)
167     {
168         /* This requires knowledge of the pixel format. */
169         FIXME("flipping x and rotating are not implemented\n");
170         return E_NOTIMPL;
171     }
172 
173     hr = IWICBitmapSource_GetSize(This->source, &srcwidth, &srcheight);
174     if (FAILED(hr)) return hr;
175 
176     if (!prc)
177     {
178         UINT width, height;
179         hr = IWICBitmapFlipRotator_GetSize(iface, &width, &height);
180         if (FAILED(hr)) return hr;
181         rect.X = 0;
182         rect.Y = 0;
183         rect.Width = width;
184         rect.Height = height;
185         prc = &rect;
186     }
187 
188     for (y=prc->Y; y - prc->Y < prc->Height; y++)
189     {
190         if (This->flip_y)
191             srcy = srcheight - 1 - y;
192         else
193             srcy = y;
194 
195         rc.X = prc->X;
196         rc.Y = srcy;
197         rc.Width = prc->Width;
198         rc.Height = 1;
199 
200         hr = IWICBitmapSource_CopyPixels(This->source, &rc, cbStride, cbStride,
201             pbBuffer);
202 
203         if (FAILED(hr)) break;
204 
205         pbBuffer += cbStride;
206     }
207 
208     return hr;
209 }
210 
211 static HRESULT WINAPI FlipRotator_Initialize(IWICBitmapFlipRotator *iface,
212     IWICBitmapSource *pISource, WICBitmapTransformOptions options)
213 {
214     FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
215     HRESULT hr=S_OK;
216 
217     TRACE("(%p,%p,%u)\n", iface, pISource, options);
218 
219     EnterCriticalSection(&This->lock);
220 
221     if (This->source)
222     {
223         hr = WINCODEC_ERR_WRONGSTATE;
224         goto end;
225     }
226 
227     if (options&WICBitmapTransformRotate90)
228     {
229         This->swap_xy = 1;
230         This->flip_x = !This->flip_x;
231     }
232 
233     if (options&WICBitmapTransformRotate180)
234     {
235         This->flip_x = !This->flip_x;
236         This->flip_y = !This->flip_y;
237     }
238 
239     if (options&WICBitmapTransformFlipHorizontal)
240         This->flip_x = !This->flip_x;
241 
242     if (options&WICBitmapTransformFlipVertical)
243         This->flip_y = !This->flip_y;
244 
245     IWICBitmapSource_AddRef(pISource);
246     This->source = pISource;
247 
248 end:
249     LeaveCriticalSection(&This->lock);
250 
251     return hr;
252 }
253 
254 static const IWICBitmapFlipRotatorVtbl FlipRotator_Vtbl = {
255     FlipRotator_QueryInterface,
256     FlipRotator_AddRef,
257     FlipRotator_Release,
258     FlipRotator_GetSize,
259     FlipRotator_GetPixelFormat,
260     FlipRotator_GetResolution,
261     FlipRotator_CopyPalette,
262     FlipRotator_CopyPixels,
263     FlipRotator_Initialize
264 };
265 
266 HRESULT FlipRotator_Create(IWICBitmapFlipRotator **fliprotator)
267 {
268     FlipRotator *This;
269 
270     This = malloc(sizeof(FlipRotator));
271     if (!This) return E_OUTOFMEMORY;
272 
273     This->IWICBitmapFlipRotator_iface.lpVtbl = &FlipRotator_Vtbl;
274     This->ref = 1;
275     This->source = NULL;
276     This->flip_x = 0;
277     This->flip_y = 0;
278     This->swap_xy = 0;
279 #ifdef __REACTOS__
280     InitializeCriticalSection(&This->lock);
281 #else
282     InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
283 #endif
284     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FlipRotator.lock");
285 
286     *fliprotator = &This->IWICBitmapFlipRotator_iface;
287 
288     return S_OK;
289 }
290