2 * Copyright 2010 Damjan Jovanovic
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.
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.
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
20 #include "wine/port.h"
24 #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
25 #define GetCurrentProcess GetCurrentProcess_Mac
26 #define GetCurrentThread GetCurrentThread_Mac
27 #define LoadResource LoadResource_Mac
28 #define EqualRect EqualRect_Mac
29 #define FillRect FillRect_Mac
30 #define FrameRect FrameRect_Mac
31 #define GetCursor GetCursor_Mac
32 #define InvertRect InvertRect_Mac
33 #define OffsetRect OffsetRect_Mac
34 #define PtInRect PtInRect_Mac
35 #define SetCursor SetCursor_Mac
36 #define SetRect SetRect_Mac
37 #define ShowCursor ShowCursor_Mac
38 #define UnionRect UnionRect_Mac
39 #include <ApplicationServices/ApplicationServices.h>
40 #undef GetCurrentProcess
41 #undef GetCurrentThread
64 #include "wincodecs_private.h"
66 #include "wine/debug.h"
67 #include "wine/library.h"
69 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
71 #if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
72 MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
74 typedef struct IcnsEncoder
{
75 IWICBitmapEncoder IWICBitmapEncoder_iface
;
78 IconFamilyHandle icns_family
;
79 BOOL any_frame_committed
;
80 int outstanding_commits
;
82 CRITICAL_SECTION lock
;
85 static inline IcnsEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
87 return CONTAINING_RECORD(iface
, IcnsEncoder
, IWICBitmapEncoder_iface
);
90 typedef struct IcnsFrameEncode
{
91 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
102 static inline IcnsFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
104 return CONTAINING_RECORD(iface
, IcnsFrameEncode
, IWICBitmapFrameEncode_iface
);
107 static HRESULT WINAPI
IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
,
110 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
111 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
113 if (!ppv
) return E_INVALIDARG
;
115 if (IsEqualIID(&IID_IUnknown
, iid
) ||
116 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
118 *ppv
= &This
->IWICBitmapFrameEncode_iface
;
123 return E_NOINTERFACE
;
126 IUnknown_AddRef((IUnknown
*)*ppv
);
130 static ULONG WINAPI
IcnsFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
132 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
133 ULONG ref
= InterlockedIncrement(&This
->ref
);
135 TRACE("(%p) refcount=%u\n", iface
, ref
);
140 static ULONG WINAPI
IcnsFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
142 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
143 ULONG ref
= InterlockedDecrement(&This
->ref
);
145 TRACE("(%p) refcount=%u\n", iface
, ref
);
149 if (!This
->committed
)
151 EnterCriticalSection(&This
->encoder
->lock
);
152 This
->encoder
->outstanding_commits
--;
153 LeaveCriticalSection(&This
->encoder
->lock
);
155 if (This
->icns_image
!= NULL
)
156 HeapFree(GetProcessHeap(), 0, This
->icns_image
);
158 IUnknown_Release((IUnknown
*)This
->encoder
);
159 HeapFree(GetProcessHeap(), 0, This
);
165 static HRESULT WINAPI
IcnsFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
,
166 IPropertyBag2
*pIEncoderOptions
)
168 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
171 TRACE("(%p,%p)\n", iface
, pIEncoderOptions
);
173 EnterCriticalSection(&This
->encoder
->lock
);
175 if (This
->initialized
)
177 hr
= WINCODEC_ERR_WRONGSTATE
;
180 This
->initialized
= TRUE
;
183 LeaveCriticalSection(&This
->encoder
->lock
);
187 static HRESULT WINAPI
IcnsFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
,
188 UINT uiWidth
, UINT uiHeight
)
190 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
193 TRACE("(%p,%u,%u)\n", iface
, uiWidth
, uiHeight
);
195 EnterCriticalSection(&This
->encoder
->lock
);
197 if (!This
->initialized
|| This
->icns_image
)
199 hr
= WINCODEC_ERR_WRONGSTATE
;
203 if (uiWidth
!= uiHeight
)
205 WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth
, uiHeight
);
220 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
225 This
->size
= uiWidth
;
228 LeaveCriticalSection(&This
->encoder
->lock
);
232 static HRESULT WINAPI
IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
,
233 double dpiX
, double dpiY
)
235 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
238 TRACE("(%p,%0.2f,%0.2f)\n", iface
, dpiX
, dpiY
);
240 EnterCriticalSection(&This
->encoder
->lock
);
242 if (!This
->initialized
|| This
->icns_image
)
244 hr
= WINCODEC_ERR_WRONGSTATE
;
249 LeaveCriticalSection(&This
->encoder
->lock
);
253 static HRESULT WINAPI
IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
,
254 WICPixelFormatGUID
*pPixelFormat
)
256 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
259 TRACE("(%p,%s)\n", iface
, debugstr_guid(pPixelFormat
));
261 EnterCriticalSection(&This
->encoder
->lock
);
263 if (!This
->initialized
|| This
->icns_image
)
265 hr
= WINCODEC_ERR_WRONGSTATE
;
269 memcpy(pPixelFormat
, &GUID_WICPixelFormat32bppBGRA
, sizeof(GUID
));
272 LeaveCriticalSection(&This
->encoder
->lock
);
276 static HRESULT WINAPI
IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
,
277 UINT cCount
, IWICColorContext
**ppIColorContext
)
279 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
283 static HRESULT WINAPI
IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
,
284 IWICPalette
*pIPalette
)
286 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
287 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
290 static HRESULT WINAPI
IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
,
291 IWICBitmapSource
*pIThumbnail
)
293 FIXME("(%p,%p): stub\n", iface
, pIThumbnail
);
294 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
297 static HRESULT WINAPI
IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
,
298 UINT lineCount
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbPixels
)
300 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
304 TRACE("(%p,%u,%u,%u,%p)\n", iface
, lineCount
, cbStride
, cbBufferSize
, pbPixels
);
306 EnterCriticalSection(&This
->encoder
->lock
);
308 if (!This
->initialized
|| !This
->size
)
310 hr
= WINCODEC_ERR_WRONGSTATE
;
313 if (lineCount
== 0 || lineCount
+ This
->lines_written
> This
->size
)
319 if (!This
->icns_image
)
323 case 16: This
->icns_type
= kIconServices16PixelDataARGB
; break;
324 case 32: This
->icns_type
= kIconServices32PixelDataARGB
; break;
325 case 48: This
->icns_type
= kIconServices48PixelDataARGB
; break;
326 case 128: This
->icns_type
= kIconServices128PixelDataARGB
; break;
327 case 256: This
->icns_type
= kIconServices256PixelDataARGB
; break;
328 case 512: This
->icns_type
= kIconServices512PixelDataARGB
; break;
330 WARN("cannot generate ICNS icon from %dx%d image\n", This
->size
, This
->size
);
334 This
->icns_image
= HeapAlloc(GetProcessHeap(), 0, This
->size
* This
->size
* 4);
335 if (!This
->icns_image
)
337 WARN("failed to allocate image buffer\n");
343 for (i
= 0; i
< lineCount
; i
++)
345 BYTE
*src_row
, *dst_row
;
347 src_row
= pbPixels
+ cbStride
* i
;
348 dst_row
= This
->icns_image
+ (This
->lines_written
+ i
)*(This
->size
*4);
349 /* swap bgr -> rgb */
350 for (j
= 0; j
< This
->size
*4; j
+= 4)
352 dst_row
[j
] = src_row
[j
+3];
353 dst_row
[j
+1] = src_row
[j
+2];
354 dst_row
[j
+2] = src_row
[j
+1];
355 dst_row
[j
+3] = src_row
[j
];
358 This
->lines_written
+= lineCount
;
361 LeaveCriticalSection(&This
->encoder
->lock
);
365 static HRESULT WINAPI
IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
,
366 IWICBitmapSource
*pIBitmapSource
, WICRect
*prc
)
368 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
371 WICPixelFormatGUID guid
;
373 BYTE
*pixeldata
= NULL
;
375 TRACE("(%p,%p,%p)\n", iface
, pIBitmapSource
, prc
);
377 if (!This
->initialized
|| !This
->size
)
379 hr
= WINCODEC_ERR_WRONGSTATE
;
383 hr
= IWICBitmapSource_GetPixelFormat(pIBitmapSource
, &guid
);
386 if (!IsEqualGUID(&guid
, &GUID_WICPixelFormat32bppBGRA
))
388 FIXME("format %s unsupported, could use WICConvertBitmapSource to convert\n", debugstr_guid(&guid
));
396 hr
= IWICBitmapSource_GetSize(pIBitmapSource
, &width
, &height
);
406 if (prc
->Width
!= This
->size
)
412 stride
= (32 * This
->size
+ 7)/8;
413 pixeldata
= HeapAlloc(GetProcessHeap(), 0, stride
* prc
->Height
);
420 hr
= IWICBitmapSource_CopyPixels(pIBitmapSource
, prc
, stride
,
421 stride
*prc
->Height
, pixeldata
);
424 hr
= IWICBitmapFrameEncode_WritePixels(iface
, prc
->Height
, stride
,
425 stride
*prc
->Height
, pixeldata
);
429 HeapFree(GetProcessHeap(), 0, pixeldata
);
433 static HRESULT WINAPI
IcnsFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
435 IcnsFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
440 TRACE("(%p): stub\n", iface
);
442 EnterCriticalSection(&This
->encoder
->lock
);
444 if (!This
->icns_image
|| This
->lines_written
!= This
->size
|| This
->committed
)
446 hr
= WINCODEC_ERR_WRONGSTATE
;
450 ret
= PtrToHand(This
->icns_image
, &handle
, This
->size
* This
->size
* 4);
451 if (ret
!= noErr
|| !handle
)
453 WARN("PtrToHand failed with error %d\n", ret
);
458 ret
= SetIconFamilyData(This
->encoder
->icns_family
, This
->icns_type
, handle
);
459 DisposeHandle(handle
);
463 WARN("SetIconFamilyData failed for image with error %d\n", ret
);
468 This
->committed
= TRUE
;
469 This
->encoder
->any_frame_committed
= TRUE
;
470 This
->encoder
->outstanding_commits
--;
473 LeaveCriticalSection(&This
->encoder
->lock
);
477 static HRESULT WINAPI
IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
,
478 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
480 FIXME("(%p, %p): stub\n", iface
, ppIMetadataQueryWriter
);
484 static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl
= {
485 IcnsFrameEncode_QueryInterface
,
486 IcnsFrameEncode_AddRef
,
487 IcnsFrameEncode_Release
,
488 IcnsFrameEncode_Initialize
,
489 IcnsFrameEncode_SetSize
,
490 IcnsFrameEncode_SetResolution
,
491 IcnsFrameEncode_SetPixelFormat
,
492 IcnsFrameEncode_SetColorContexts
,
493 IcnsFrameEncode_SetPalette
,
494 IcnsFrameEncode_SetThumbnail
,
495 IcnsFrameEncode_WritePixels
,
496 IcnsFrameEncode_WriteSource
,
497 IcnsFrameEncode_Commit
,
498 IcnsFrameEncode_GetMetadataQueryWriter
501 static HRESULT WINAPI
IcnsEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
,
504 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
505 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
507 if (!ppv
) return E_INVALIDARG
;
509 if (IsEqualIID(&IID_IUnknown
, iid
) ||
510 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
517 return E_NOINTERFACE
;
520 IUnknown_AddRef((IUnknown
*)*ppv
);
524 static ULONG WINAPI
IcnsEncoder_AddRef(IWICBitmapEncoder
*iface
)
526 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
527 ULONG ref
= InterlockedIncrement(&This
->ref
);
529 TRACE("(%p) refcount=%u\n", iface
, ref
);
534 static ULONG WINAPI
IcnsEncoder_Release(IWICBitmapEncoder
*iface
)
536 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
537 ULONG ref
= InterlockedDecrement(&This
->ref
);
539 TRACE("(%p) refcount=%u\n", iface
, ref
);
543 This
->lock
.DebugInfo
->Spare
[0] = 0;
544 DeleteCriticalSection(&This
->lock
);
545 if (This
->icns_family
)
546 DisposeHandle((Handle
)This
->icns_family
);
548 IStream_Release(This
->stream
);
549 HeapFree(GetProcessHeap(), 0, This
);
555 static HRESULT WINAPI
IcnsEncoder_Initialize(IWICBitmapEncoder
*iface
,
556 IStream
*pIStream
, WICBitmapEncoderCacheOption cacheOption
)
558 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
561 TRACE("(%p,%p,%u)\n", iface
, pIStream
, cacheOption
);
563 EnterCriticalSection(&This
->lock
);
565 if (This
->icns_family
)
567 hr
= WINCODEC_ERR_WRONGSTATE
;
570 This
->icns_family
= (IconFamilyHandle
)NewHandle(0);
571 if (!This
->icns_family
)
573 WARN("error creating icns family\n");
577 IStream_AddRef(pIStream
);
578 This
->stream
= pIStream
;
581 LeaveCriticalSection(&This
->lock
);
586 static HRESULT WINAPI
IcnsEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
,
587 GUID
*pguidContainerFormat
)
589 FIXME("(%p,%s): stub\n", iface
, debugstr_guid(pguidContainerFormat
));
593 static HRESULT WINAPI
IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
,
594 IWICBitmapEncoderInfo
**ppIEncoderInfo
)
596 FIXME("(%p,%p): stub\n", iface
, ppIEncoderInfo
);
600 static HRESULT WINAPI
IcnsEncoder_SetColorContexts(IWICBitmapEncoder
*iface
,
601 UINT cCount
, IWICColorContext
**ppIColorContext
)
603 FIXME("(%p,%u,%p): stub\n", iface
, cCount
, ppIColorContext
);
607 static HRESULT WINAPI
IcnsEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*pIPalette
)
609 TRACE("(%p,%p)\n", iface
, pIPalette
);
610 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
613 static HRESULT WINAPI
IcnsEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIThumbnail
)
615 TRACE("(%p,%p)\n", iface
, pIThumbnail
);
616 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
619 static HRESULT WINAPI
IcnsEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*pIPreview
)
621 TRACE("(%p,%p)\n", iface
, pIPreview
);
622 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
625 static HRESULT WINAPI
IcnsEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
,
626 IWICBitmapFrameEncode
**ppIFrameEncode
, IPropertyBag2
**ppIEncoderOptions
)
628 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
630 IcnsFrameEncode
*frameEncode
= NULL
;
632 TRACE("(%p,%p,%p)\n", iface
, ppIFrameEncode
, ppIEncoderOptions
);
634 EnterCriticalSection(&This
->lock
);
636 if (!This
->icns_family
)
638 hr
= WINCODEC_ERR_NOTINITIALIZED
;
642 hr
= CreatePropertyBag2(ppIEncoderOptions
);
646 frameEncode
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode
));
647 if (frameEncode
== NULL
)
652 frameEncode
->IWICBitmapFrameEncode_iface
.lpVtbl
= &IcnsEncoder_FrameVtbl
;
653 frameEncode
->encoder
= This
;
654 frameEncode
->ref
= 1;
655 frameEncode
->initialized
= FALSE
;
656 frameEncode
->size
= 0;
657 frameEncode
->icns_image
= NULL
;
658 frameEncode
->lines_written
= 0;
659 frameEncode
->committed
= FALSE
;
660 *ppIFrameEncode
= &frameEncode
->IWICBitmapFrameEncode_iface
;
661 This
->outstanding_commits
++;
662 IUnknown_AddRef((IUnknown
*)This
);
665 LeaveCriticalSection(&This
->lock
);
670 static HRESULT WINAPI
IcnsEncoder_Commit(IWICBitmapEncoder
*iface
)
672 IcnsEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
677 TRACE("(%p)\n", iface
);
679 EnterCriticalSection(&This
->lock
);
681 if (!This
->any_frame_committed
|| This
->outstanding_commits
> 0 || This
->committed
)
683 hr
= WINCODEC_ERR_WRONGSTATE
;
687 buffer_size
= GetHandleSize((Handle
)This
->icns_family
);
688 hr
= IStream_Write(This
->stream
, *This
->icns_family
, buffer_size
, &byteswritten
);
689 if (FAILED(hr
) || byteswritten
!= buffer_size
)
691 WARN("writing file failed, hr = 0x%08X\n", hr
);
696 This
->committed
= TRUE
;
699 LeaveCriticalSection(&This
->lock
);
703 static HRESULT WINAPI
IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
,
704 IWICMetadataQueryWriter
**ppIMetadataQueryWriter
)
706 FIXME("(%p,%p): stub\n", iface
, ppIMetadataQueryWriter
);
710 static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl
= {
711 IcnsEncoder_QueryInterface
,
714 IcnsEncoder_Initialize
,
715 IcnsEncoder_GetContainerFormat
,
716 IcnsEncoder_GetEncoderInfo
,
717 IcnsEncoder_SetColorContexts
,
718 IcnsEncoder_SetPalette
,
719 IcnsEncoder_SetThumbnail
,
720 IcnsEncoder_SetPreview
,
721 IcnsEncoder_CreateNewFrame
,
723 IcnsEncoder_GetMetadataQueryWriter
726 HRESULT
IcnsEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
731 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
735 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
737 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder
));
738 if (!This
) return E_OUTOFMEMORY
;
740 This
->IWICBitmapEncoder_iface
.lpVtbl
= &IcnsEncoder_Vtbl
;
743 This
->icns_family
= NULL
;
744 This
->any_frame_committed
= FALSE
;
745 This
->outstanding_commits
= 0;
746 This
->committed
= FALSE
;
747 InitializeCriticalSection(&This
->lock
);
748 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": IcnsEncoder.lock");
750 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
751 IUnknown_Release((IUnknown
*)This
);
756 #else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
757 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
759 HRESULT
IcnsEncoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
761 ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");