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