1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thumbviewer.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_shell.hxx"
33 #include "internal/global.hxx"
35 #ifndef INFOTIPS_HXX_INCLUDED
36 #include "internal/thumbviewer.hxx"
38 #include "internal/shlxthdl.hxx"
39 #include "internal/utilities.hxx"
40 #include "internal/registry.hxx"
41 #include "internal/fileextensions.hxx"
42 #include "internal/config.hxx"
43 #include "internal/zipfile.hxx"
45 #include "internal/resource.h"
51 #pragma warning(push, 1)
59 extern HINSTANCE g_hModule
;
63 /* The signet.png used for thumbnails of signed documents
64 is contained as resource in this module, the resource
66 void LoadSignetImageFromResource(ZipFile::ZipContentBuffer_t
& buffer
)
68 HRSRC hrc
= FindResource(g_hModule
, TEXT("#2000"), RT_RCDATA
);
69 DWORD size
= SizeofResource(g_hModule
, hrc
);
70 HGLOBAL hglob
= LoadResource(g_hModule
, hrc
);
71 char* data
= reinterpret_cast<char*>(LockResource(hglob
));
72 buffer
= ZipFile::ZipContentBuffer_t(data
, data
+ size
);
75 bool IsSignedDocument(const ZipFile
* zipfile
)
77 return zipfile
->HasContent("META-INF/documentsignatures.xml");
83 ZeroMemory(&osvi
, sizeof(osvi
));
84 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
87 return ((osvi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) &&
88 ((osvi
.dwMajorVersion
>= 5) && (osvi
.dwMinorVersion
>= 1)));
91 /* Calculate where to position the signet image.
92 On Windows ME we need to shift the signet a
93 little bit to the left because Windows ME
94 puts an overlay icon to the lower right
95 corner of a thumbnail image so that our signet
97 Gdiplus::Point
CalcSignetPosition(
98 const Gdiplus::Rect
& canvas
, const Gdiplus::Rect
& thumbnail_border
, const Gdiplus::Rect
& signet
)
102 int hoffset
= canvas
.GetRight() - thumbnail_border
.GetRight();
103 int voffset
= canvas
.GetBottom() - thumbnail_border
.GetBottom();
105 if (hoffset
> voffset
)
107 x
= thumbnail_border
.GetRight() - signet
.GetRight() + min(signet
.GetRight() / 2, hoffset
);
108 y
= thumbnail_border
.GetBottom() - signet
.GetBottom();
112 x
= thumbnail_border
.GetRight() - signet
.GetRight();
113 y
= thumbnail_border
.GetBottom() - signet
.GetBottom() + min(signet
.GetBottom() / 2, voffset
);
119 return Gdiplus::Point(x
,y
);
123 class StreamOnZipBuffer
: public IStream
126 StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t
& zip_buffer
);
129 virtual ULONG STDMETHODCALLTYPE
AddRef();
130 virtual ULONG STDMETHODCALLTYPE
Release( void);
131 virtual HRESULT STDMETHODCALLTYPE
QueryInterface(REFIID riid
, void __RPC_FAR
*__RPC_FAR
*ppvObject
);
134 virtual HRESULT STDMETHODCALLTYPE
Read(void *pv
, ULONG cb
, ULONG
*pcbRead
);
135 virtual HRESULT STDMETHODCALLTYPE
Write(void const *pv
, ULONG cb
, ULONG
*pcbWritten
);
136 virtual HRESULT STDMETHODCALLTYPE
Seek(LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*plibNewPosition
);
137 virtual HRESULT STDMETHODCALLTYPE
SetSize(ULARGE_INTEGER libNewSize
);
138 virtual HRESULT STDMETHODCALLTYPE
CopyTo(IStream
*pstm
, ULARGE_INTEGER cb
, ULARGE_INTEGER
*pcbRead
, ULARGE_INTEGER
*pcbWritten
);
139 virtual HRESULT STDMETHODCALLTYPE
Commit(DWORD grfCommitFlags
);
140 virtual HRESULT STDMETHODCALLTYPE
Revert(void);
141 virtual HRESULT STDMETHODCALLTYPE
LockRegion(ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
);
142 virtual HRESULT STDMETHODCALLTYPE
UnlockRegion(ULARGE_INTEGER libOffset
, ULARGE_INTEGER cb
, DWORD dwLockType
);
143 virtual HRESULT STDMETHODCALLTYPE
Stat(STATSTG
*pstatstg
, DWORD grfStatFlag
);
144 virtual HRESULT STDMETHODCALLTYPE
Clone(IStream
**ppstm
);
148 const ZipFile::ZipContentBuffer_t
& ref_zip_buffer_
;
152 StreamOnZipBuffer::StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t
& zip_buffer
) :
154 ref_zip_buffer_(zip_buffer
),
161 ULONG STDMETHODCALLTYPE
StreamOnZipBuffer::AddRef(void)
163 return InterlockedIncrement(&ref_count_
);
166 ULONG STDMETHODCALLTYPE
StreamOnZipBuffer::Release( void)
168 long refcnt
= InterlockedDecrement(&ref_count_
);
176 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::QueryInterface(REFIID riid
, void __RPC_FAR
*__RPC_FAR
*ppvObject
)
181 if ((IID_IUnknown
== riid
) || (IID_IStream
== riid
))
183 pUnk
= static_cast<IStream
*>(this);
188 return E_NOINTERFACE
;
191 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Read(void *pv
, ULONG cb
, ULONG
*pcbRead
)
194 return STG_E_INVALIDPOINTER
;
196 size_t size
= ref_zip_buffer_
.size();
201 char* p
= reinterpret_cast<char*>(pv
);
204 for ( ;(pos_
< size
) && (cb
> 0); pos_
++, cb
--, read
++)
205 *p
++ = ref_zip_buffer_
[pos_
];
213 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Seek(LARGE_INTEGER dlibMove
, DWORD dwOrigin
, ULARGE_INTEGER
*)
215 size_t size
= ref_zip_buffer_
.size();
220 case STREAM_SEEK_SET
:
222 case STREAM_SEEK_CUR
:
225 case STREAM_SEEK_END
:
230 HRESULT hr
= STG_E_INVALIDFUNCTION
;
232 p
+= dlibMove
.LowPart
;
241 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Stat(STATSTG
*pstatstg
, DWORD grfStatFlag
)
243 if (pstatstg
== NULL
)
244 return STG_E_INVALIDPOINTER
;
246 ZeroMemory(pstatstg
, sizeof(STATSTG
));
248 if (grfStatFlag
== STATFLAG_DEFAULT
)
250 size_t sz
= 4 * sizeof(wchar_t);
251 wchar_t* name
= reinterpret_cast<wchar_t*>(CoTaskMemAlloc(sz
));
252 ZeroMemory(name
, sz
);
253 memcpy(name
, L
"png", 3 * sizeof(wchar_t));
254 pstatstg
->pwcsName
= name
;
257 pstatstg
->type
= STGTY_LOCKBYTES
;
260 uli
.LowPart
= ref_zip_buffer_
.size();
263 pstatstg
->cbSize
= uli
;
268 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Write(void const *, ULONG
, ULONG
*)
269 { return E_NOTIMPL
; }
271 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::SetSize(ULARGE_INTEGER
)
272 { return E_NOTIMPL
; }
274 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::CopyTo(IStream
*, ULARGE_INTEGER
, ULARGE_INTEGER
*, ULARGE_INTEGER
*)
275 { return E_NOTIMPL
; }
277 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Commit(DWORD
)
278 { return E_NOTIMPL
; }
280 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Revert(void)
281 { return E_NOTIMPL
; }
283 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::LockRegion(ULARGE_INTEGER
, ULARGE_INTEGER
, DWORD
)
284 { return E_NOTIMPL
; }
286 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::UnlockRegion(ULARGE_INTEGER
, ULARGE_INTEGER
, DWORD
)
287 { return E_NOTIMPL
; }
289 HRESULT STDMETHODCALLTYPE
StreamOnZipBuffer::Clone(IStream
**)
290 { return E_NOTIMPL
; }
293 //#########################################
296 CThumbviewer::CThumbviewer(long RefCnt
) :
299 InterlockedIncrement(&g_DllRefCnt
);
301 thumbnail_size_
.cx
= 0;
302 thumbnail_size_
.cy
= 0;
304 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
305 Gdiplus::GdiplusStartup(&gdiplus_token_
, &gdiplusStartupInput
, NULL
);
307 ZipFile::ZipContentBuffer_t img_data
;
308 internal::LoadSignetImageFromResource(img_data
);
309 IStream
* stream
= new StreamOnZipBuffer(img_data
);
310 signet_
= new Gdiplus::Bitmap(stream
, TRUE
);
314 CThumbviewer::~CThumbviewer()
317 Gdiplus::GdiplusShutdown(gdiplus_token_
);
318 InterlockedDecrement(&g_DllRefCnt
);
323 HRESULT STDMETHODCALLTYPE
CThumbviewer::QueryInterface(REFIID riid
, void __RPC_FAR
*__RPC_FAR
*ppvObject
)
328 if ((IID_IUnknown
== riid
) || (IID_IPersistFile
== riid
))
330 pUnk
= static_cast<IPersistFile
*>(this);
335 else if (IID_IExtractImage
== riid
)
337 pUnk
= static_cast<IExtractImage
*>(this);
342 return E_NOINTERFACE
;
345 ULONG STDMETHODCALLTYPE
CThumbviewer::AddRef(void)
347 return InterlockedIncrement(&ref_count_
);
350 ULONG STDMETHODCALLTYPE
CThumbviewer::Release( void)
352 long refcnt
= InterlockedDecrement(&ref_count_
);
360 // IExtractImage2 methods
362 const std::string THUMBNAIL_CONTENT
= "Thumbnails/thumbnail.png";
364 HRESULT STDMETHODCALLTYPE
CThumbviewer::Extract(HBITMAP
*phBmpImage
)
370 std::auto_ptr
<ZipFile
> zipfile(new ZipFile(WStringToString(filename_
)));
372 if (zipfile
->HasContent(THUMBNAIL_CONTENT
))
374 ZipFile::ZipContentBuffer_t thumbnail
;
375 zipfile
->GetUncompressedContent(THUMBNAIL_CONTENT
, thumbnail
);
376 IStream
* stream
= new StreamOnZipBuffer(thumbnail
);
378 Gdiplus::Bitmap
thumbnail_png(stream
, TRUE
);
380 if ((thumbnail_png
.GetHeight() == 0) || (thumbnail_png
.GetWidth() == 0))
386 HWND hwnd
= GetDesktopWindow();
387 HDC hdc
= GetDC(hwnd
);
388 HDC memDC
= CreateCompatibleDC(hdc
);
392 UINT offset
= 3; // reserve a little border space
394 Gdiplus::Rect
canvas(0, 0, thumbnail_size_
.cx
, thumbnail_size_
.cy
);
395 Gdiplus::Rect
canvas_thumbnail(offset
, offset
, thumbnail_size_
.cx
- 2 * offset
, thumbnail_size_
.cy
- 2 * offset
);
397 Gdiplus::Rect scaledRect
= CalcScaledAspectRatio(
398 Gdiplus::Rect(0, 0, thumbnail_png
.GetWidth(), thumbnail_png
.GetHeight()), canvas_thumbnail
);
405 ZeroMemory(&dib
, sizeof(dib
));
407 dib
.bi
.biSize
= sizeof(BITMAPINFOHEADER
);
408 dib
.bi
.biWidth
= thumbnail_size_
.cx
;
409 dib
.bi
.biHeight
= thumbnail_size_
.cy
;
411 dib
.bi
.biBitCount
= static_cast<WORD
>(color_depth_
);
412 dib
.bi
.biCompression
= BI_RGB
;
415 HBITMAP hMemBmp
= CreateDIBSection(memDC
, (LPBITMAPINFO
)&dib
, DIB_RGB_COLORS
, &lpBits
, NULL
, 0);
416 HGDIOBJ hOldObj
= SelectObject(memDC
, hMemBmp
);
418 Gdiplus::Graphics
graphics(memDC
);
419 Gdiplus::Pen
blackPen(Gdiplus::Color(255, 0, 0, 0), 1);
421 Gdiplus::SolidBrush
whiteBrush(Gdiplus::Color(255, 255, 255, 255));
422 graphics
.FillRectangle(&whiteBrush
, canvas
);
424 scaledRect
.X
= (canvas
.Width
- scaledRect
.Width
) / 2;
425 scaledRect
.Y
= (canvas
.Height
- scaledRect
.Height
) / 2;
427 Gdiplus::Rect
border_rect(scaledRect
.X
, scaledRect
.Y
, scaledRect
.Width
, scaledRect
.Height
);
428 graphics
.DrawRectangle(&blackPen
, border_rect
);
432 scaledRect
.Width
-= 1;
433 scaledRect
.Height
-= 1;
435 graphics
.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic
);
436 Gdiplus::Status stat
= graphics
.DrawImage(
437 &thumbnail_png
, scaledRect
, 0 , 0,
438 thumbnail_png
.GetWidth(), thumbnail_png
.GetHeight(), Gdiplus::UnitPixel
);
440 /* Add a signet sign to the thumbnail of signed documents */
441 if (internal::IsSignedDocument(zipfile
.get()))
443 double SCALING_FACTOR
= 0.6;
444 Gdiplus::Rect
signet_scaled(
445 0, 0, static_cast<INT
>(signet_
->GetWidth() * SCALING_FACTOR
), static_cast<INT
>(signet_
->GetHeight() * SCALING_FACTOR
));
446 Gdiplus::Point pos_signet
= internal::CalcSignetPosition(canvas_thumbnail
, border_rect
, signet_scaled
);
447 Gdiplus::Rect
dest(pos_signet
.X
, pos_signet
.Y
, signet_scaled
.GetRight(), signet_scaled
.GetBottom());
449 stat
= graphics
.DrawImage(
451 0, 0, signet_
->GetWidth(), signet_
->GetHeight(),
455 if (stat
== Gdiplus::Ok
)
457 *phBmpImage
= hMemBmp
;
461 SelectObject(memDC
, hOldObj
);
465 ReleaseDC(hwnd
, hdc
);
469 catch(std::exception
&)
476 HRESULT STDMETHODCALLTYPE
CThumbviewer::GetLocation(
477 LPWSTR pszPathBuffer
, DWORD cchMax
, DWORD
*pdwPriority
, const SIZE
*prgSize
, DWORD dwRecClrDepth
, DWORD
*pdwFlags
)
479 if ((prgSize
== NULL
) || (pdwFlags
== NULL
) || ((*pdwFlags
& IEIFLAG_ASYNC
) && (pdwPriority
== NULL
)))
482 thumbnail_size_
= *prgSize
;
483 color_depth_
= dwRecClrDepth
;
485 *pdwFlags
= IEIFLAG_CACHE
; // we don't cache the image
487 wcsncpy(pszPathBuffer
, filename_
.c_str(), cchMax
);
494 HRESULT STDMETHODCALLTYPE
CThumbviewer::GetClassID(CLSID
* pClassID
)
496 pClassID
= const_cast<CLSID
*>(&CLSID_THUMBVIEWER_HANDLER
);
500 // IPersistFile methods
502 HRESULT STDMETHODCALLTYPE
CThumbviewer::Load(LPCOLESTR pszFileName
, DWORD
)
504 filename_
= pszFileName
;
508 HRESULT STDMETHODCALLTYPE
CThumbviewer::IsDirty()
509 { return E_NOTIMPL
; }
511 HRESULT STDMETHODCALLTYPE
CThumbviewer::Save(LPCOLESTR
, BOOL
)
512 { return E_NOTIMPL
; }
514 HRESULT STDMETHODCALLTYPE
CThumbviewer::SaveCompleted(LPCOLESTR
)
515 { return E_NOTIMPL
; }
517 HRESULT STDMETHODCALLTYPE
CThumbviewer::GetCurFile(LPOLESTR __RPC_FAR
*)
518 { return E_NOTIMPL
; }
521 Gdiplus::Rect
CThumbviewer::CalcScaledAspectRatio(Gdiplus::Rect src
, Gdiplus::Rect dest
)
523 Gdiplus::Rect result
;
524 if (src
.Width
>= src
.Height
)
525 result
= Gdiplus::Rect(0, 0, dest
.Width
, src
.Height
* dest
.Width
/ src
.Width
);
527 result
= Gdiplus::Rect(0, 0, src
.Width
* dest
.Height
/ src
.Height
, dest
.Height
);