Synchronize with trunk r58528.
[reactos.git] / dll / win32 / windowscodecs / fliprotate.c
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 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #include <config.h>
24
25 #include <stdarg.h>
26
27 #define COBJMACROS
28
29 #include <windef.h>
30 #include <winbase.h>
31 #include <objbase.h>
32 #include <wincodec.h>
33
34 //#include "wincodecs_private.h"
35
36 #include <wine/debug.h>
37
38 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
39
40 typedef struct FlipRotator {
41 IWICBitmapFlipRotator IWICBitmapFlipRotator_iface;
42 LONG ref;
43 IWICBitmapSource *source;
44 int flip_x;
45 int flip_y;
46 int swap_xy;
47 CRITICAL_SECTION lock; /* must be held when initialized */
48 } FlipRotator;
49
50 static inline FlipRotator *impl_from_IWICBitmapFlipRotator(IWICBitmapFlipRotator *iface)
51 {
52 return CONTAINING_RECORD(iface, FlipRotator, IWICBitmapFlipRotator_iface);
53 }
54
55 static HRESULT WINAPI FlipRotator_QueryInterface(IWICBitmapFlipRotator *iface, REFIID iid,
56 void **ppv)
57 {
58 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
59 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
60
61 if (!ppv) return E_INVALIDARG;
62
63 if (IsEqualIID(&IID_IUnknown, iid) ||
64 IsEqualIID(&IID_IWICBitmapSource, iid) ||
65 IsEqualIID(&IID_IWICBitmapFlipRotator, iid))
66 {
67 *ppv = &This->IWICBitmapFlipRotator_iface;
68 }
69 else
70 {
71 *ppv = NULL;
72 return E_NOINTERFACE;
73 }
74
75 IUnknown_AddRef((IUnknown*)*ppv);
76 return S_OK;
77 }
78
79 static ULONG WINAPI FlipRotator_AddRef(IWICBitmapFlipRotator *iface)
80 {
81 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
82 ULONG ref = InterlockedIncrement(&This->ref);
83
84 TRACE("(%p) refcount=%u\n", iface, ref);
85
86 return ref;
87 }
88
89 static ULONG WINAPI FlipRotator_Release(IWICBitmapFlipRotator *iface)
90 {
91 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
92 ULONG ref = InterlockedDecrement(&This->ref);
93
94 TRACE("(%p) refcount=%u\n", iface, ref);
95
96 if (ref == 0)
97 {
98 This->lock.DebugInfo->Spare[0] = 0;
99 DeleteCriticalSection(&This->lock);
100 if (This->source) IWICBitmapSource_Release(This->source);
101 HeapFree(GetProcessHeap(), 0, This);
102 }
103
104 return ref;
105 }
106
107 static HRESULT WINAPI FlipRotator_GetSize(IWICBitmapFlipRotator *iface,
108 UINT *puiWidth, UINT *puiHeight)
109 {
110 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
111 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
112
113 if (!This->source)
114 return WINCODEC_ERR_WRONGSTATE;
115 else if (This->swap_xy)
116 return IWICBitmapSource_GetSize(This->source, puiHeight, puiWidth);
117 else
118 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
119 }
120
121 static HRESULT WINAPI FlipRotator_GetPixelFormat(IWICBitmapFlipRotator *iface,
122 WICPixelFormatGUID *pPixelFormat)
123 {
124 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
125 TRACE("(%p,%p)\n", iface, pPixelFormat);
126
127 if (!This->source)
128 return WINCODEC_ERR_WRONGSTATE;
129 else
130 return IWICBitmapSource_GetPixelFormat(This->source, pPixelFormat);
131 }
132
133 static HRESULT WINAPI FlipRotator_GetResolution(IWICBitmapFlipRotator *iface,
134 double *pDpiX, double *pDpiY)
135 {
136 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
137 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
138
139 if (!This->source)
140 return WINCODEC_ERR_WRONGSTATE;
141 else if (This->swap_xy)
142 return IWICBitmapSource_GetResolution(This->source, pDpiY, pDpiX);
143 else
144 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
145 }
146
147 static HRESULT WINAPI FlipRotator_CopyPalette(IWICBitmapFlipRotator *iface,
148 IWICPalette *pIPalette)
149 {
150 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
151 TRACE("(%p,%p)\n", iface, pIPalette);
152
153 if (!This->source)
154 return WINCODEC_ERR_WRONGSTATE;
155 else
156 return IWICBitmapSource_CopyPalette(This->source, pIPalette);
157 }
158
159 static HRESULT WINAPI FlipRotator_CopyPixels(IWICBitmapFlipRotator *iface,
160 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
161 {
162 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
163 HRESULT hr;
164 UINT y;
165 UINT srcy, srcwidth, srcheight;
166 WICRect rc;
167 WICRect rect;
168
169 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
170
171 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
172
173 if (This->swap_xy || This->flip_x)
174 {
175 /* This requires knowledge of the pixel format. */
176 FIXME("flipping x and rotating are not implemented\n");
177 return E_NOTIMPL;
178 }
179
180 hr = IWICBitmapSource_GetSize(This->source, &srcwidth, &srcheight);
181 if (FAILED(hr)) return hr;
182
183 if (!prc)
184 {
185 UINT width, height;
186 hr = IWICBitmapFlipRotator_GetSize(iface, &width, &height);
187 if (FAILED(hr)) return hr;
188 rect.X = 0;
189 rect.Y = 0;
190 rect.Width = width;
191 rect.Height = height;
192 prc = &rect;
193 }
194
195 for (y=prc->Y; y - prc->Y < prc->Height; y++)
196 {
197 if (This->flip_y)
198 srcy = srcheight - 1 - y;
199 else
200 srcy = y;
201
202 rc.X = prc->X;
203 rc.Y = srcy;
204 rc.Width = prc->Width;
205 rc.Height = 1;
206
207 hr = IWICBitmapSource_CopyPixels(This->source, &rc, cbStride, cbStride,
208 pbBuffer);
209
210 if (FAILED(hr)) break;
211
212 pbBuffer += cbStride;
213 }
214
215 return hr;
216 }
217
218 static HRESULT WINAPI FlipRotator_Initialize(IWICBitmapFlipRotator *iface,
219 IWICBitmapSource *pISource, WICBitmapTransformOptions options)
220 {
221 FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
222 HRESULT hr=S_OK;
223
224 TRACE("(%p,%p,%u)\n", iface, pISource, options);
225
226 EnterCriticalSection(&This->lock);
227
228 if (This->source)
229 {
230 hr = WINCODEC_ERR_WRONGSTATE;
231 goto end;
232 }
233
234 if (options&WICBitmapTransformRotate90)
235 {
236 This->swap_xy = 1;
237 This->flip_x = !This->flip_x;
238 }
239
240 if (options&WICBitmapTransformRotate180)
241 {
242 This->flip_x = !This->flip_x;
243 This->flip_y = !This->flip_y;
244 }
245
246 if (options&WICBitmapTransformFlipHorizontal)
247 This->flip_x = !This->flip_x;
248
249 if (options&WICBitmapTransformFlipVertical)
250 This->flip_y = !This->flip_y;
251
252 IWICBitmapSource_AddRef(pISource);
253 This->source = pISource;
254
255 end:
256 LeaveCriticalSection(&This->lock);
257
258 return hr;
259 }
260
261 static const IWICBitmapFlipRotatorVtbl FlipRotator_Vtbl = {
262 FlipRotator_QueryInterface,
263 FlipRotator_AddRef,
264 FlipRotator_Release,
265 FlipRotator_GetSize,
266 FlipRotator_GetPixelFormat,
267 FlipRotator_GetResolution,
268 FlipRotator_CopyPalette,
269 FlipRotator_CopyPixels,
270 FlipRotator_Initialize
271 };
272
273 HRESULT FlipRotator_Create(IWICBitmapFlipRotator **fliprotator)
274 {
275 FlipRotator *This;
276
277 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FlipRotator));
278 if (!This) return E_OUTOFMEMORY;
279
280 This->IWICBitmapFlipRotator_iface.lpVtbl = &FlipRotator_Vtbl;
281 This->ref = 1;
282 This->source = NULL;
283 This->flip_x = 0;
284 This->flip_y = 0;
285 This->swap_xy = 0;
286 InitializeCriticalSection(&This->lock);
287 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FlipRotator.lock");
288
289 *fliprotator = &This->IWICBitmapFlipRotator_iface;
290
291 return S_OK;
292 }