update dev300-m58
[ooovba.git] / shell / source / win32 / shlxthandler / thumbviewer / thumbviewer.cxx
blob9c9952e05703552b5195baab10c14258508dc1b9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thumbviewer.cxx,v $
10 * $Revision: 1.7 $
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"
37 #endif
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"
46 #include <stdio.h>
47 #include <utility>
48 #include <stdlib.h>
50 #if defined _MSC_VER
51 #pragma warning(push, 1)
52 #endif
53 #include <shellapi.h>
54 #if defined _MSC_VER
55 #pragma warning(pop)
56 #endif
57 #include <memory>
59 extern HINSTANCE g_hModule;
61 namespace internal
63 /* The signet.png used for thumbnails of signed documents
64 is contained as resource in this module, the resource
65 id is 2000 */
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");
80 bool IsWindowsXP()
82 OSVERSIONINFO osvi;
83 ZeroMemory(&osvi, sizeof(osvi));
84 osvi.dwOSVersionInfoSize = sizeof(osvi);
85 GetVersionEx(&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
96 we be hidden. */
97 Gdiplus::Point CalcSignetPosition(
98 const Gdiplus::Rect& canvas, const Gdiplus::Rect& thumbnail_border, const Gdiplus::Rect& signet)
100 int x = 0;
101 int y = 0;
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();
110 else
112 x = thumbnail_border.GetRight() - signet.GetRight();
113 y = thumbnail_border.GetBottom() - signet.GetBottom() + min(signet.GetBottom() / 2, voffset);
116 if (!IsWindowsXP())
117 x -= 15;
119 return Gdiplus::Point(x,y);
123 class StreamOnZipBuffer : public IStream
125 public:
126 StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer);
128 // IUnknown
129 virtual ULONG STDMETHODCALLTYPE AddRef();
130 virtual ULONG STDMETHODCALLTYPE Release( void);
131 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject);
133 // IStream
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);
146 private:
147 LONG ref_count_;
148 const ZipFile::ZipContentBuffer_t& ref_zip_buffer_;
149 size_t pos_;
152 StreamOnZipBuffer::StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer) :
153 ref_count_(1),
154 ref_zip_buffer_(zip_buffer),
155 pos_(0)
159 // IUnknown methods
161 ULONG STDMETHODCALLTYPE StreamOnZipBuffer::AddRef(void)
163 return InterlockedIncrement(&ref_count_);
166 ULONG STDMETHODCALLTYPE StreamOnZipBuffer::Release( void)
168 long refcnt = InterlockedDecrement(&ref_count_);
170 if (0 == ref_count_)
171 delete this;
173 return refcnt;
176 HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
178 *ppvObject = 0;
179 IUnknown* pUnk = 0;
181 if ((IID_IUnknown == riid) || (IID_IStream == riid))
183 pUnk = static_cast<IStream*>(this);
184 pUnk->AddRef();
185 *ppvObject = pUnk;
186 return S_OK;
188 return E_NOINTERFACE;
191 HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Read(void *pv, ULONG cb, ULONG *pcbRead)
193 if (pv == NULL)
194 return STG_E_INVALIDPOINTER;
196 size_t size = ref_zip_buffer_.size();
198 if (pos_ > size)
199 return S_FALSE;
201 char* p = reinterpret_cast<char*>(pv);
202 ULONG read = 0;
204 for ( ;(pos_ < size) && (cb > 0); pos_++, cb--, read++)
205 *p++ = ref_zip_buffer_[pos_];
207 if (pcbRead)
208 *pcbRead = read;
210 return S_OK;
213 HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *)
215 size_t size = ref_zip_buffer_.size();
216 size_t p = 0;
218 switch (dwOrigin)
220 case STREAM_SEEK_SET:
221 break;
222 case STREAM_SEEK_CUR:
223 p = pos_;
224 break;
225 case STREAM_SEEK_END:
226 p = size - 1;
227 break;
230 HRESULT hr = STG_E_INVALIDFUNCTION;
232 p += dlibMove.LowPart;
233 if (p < size)
235 pos_ = p;
236 hr = S_OK;
238 return hr;
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;
259 ULARGE_INTEGER uli;
260 uli.LowPart = ref_zip_buffer_.size();
261 uli.HighPart = 0;
263 pstatstg->cbSize = uli;
265 return S_OK;
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) :
297 ref_count_(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);
311 stream->Release();
314 CThumbviewer::~CThumbviewer()
316 delete signet_;
317 Gdiplus::GdiplusShutdown(gdiplus_token_);
318 InterlockedDecrement(&g_DllRefCnt);
321 // IUnknown methods
323 HRESULT STDMETHODCALLTYPE CThumbviewer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject)
325 *ppvObject = 0;
326 IUnknown* pUnk = 0;
328 if ((IID_IUnknown == riid) || (IID_IPersistFile == riid))
330 pUnk = static_cast<IPersistFile*>(this);
331 pUnk->AddRef();
332 *ppvObject = pUnk;
333 return S_OK;
335 else if (IID_IExtractImage == riid)
337 pUnk = static_cast<IExtractImage*>(this);
338 pUnk->AddRef();
339 *ppvObject = pUnk;
340 return S_OK;
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_);
354 if (0 == ref_count_)
355 delete this;
357 return refcnt;
360 // IExtractImage2 methods
362 const std::string THUMBNAIL_CONTENT = "Thumbnails/thumbnail.png";
364 HRESULT STDMETHODCALLTYPE CThumbviewer::Extract(HBITMAP *phBmpImage)
366 HRESULT hr = E_FAIL;
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))
382 stream->Release();
383 return E_FAIL;
386 HWND hwnd = GetDesktopWindow();
387 HDC hdc = GetDC(hwnd);
388 HDC memDC = CreateCompatibleDC(hdc);
390 if (memDC)
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);
400 struct {
401 BITMAPINFOHEADER bi;
402 DWORD ct[256];
403 } dib;
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;
410 dib.bi.biPlanes = 1;
411 dib.bi.biBitCount = static_cast<WORD>(color_depth_);
412 dib.bi.biCompression = BI_RGB;
414 LPVOID lpBits;
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);
430 scaledRect.X += 1;
431 scaledRect.Y += 1;
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(
450 signet_, dest,
451 0, 0, signet_->GetWidth(), signet_->GetHeight(),
452 Gdiplus::UnitPixel);
455 if (stat == Gdiplus::Ok)
457 *phBmpImage = hMemBmp;
458 hr = NOERROR;
461 SelectObject(memDC, hOldObj);
462 DeleteDC(memDC);
465 ReleaseDC(hwnd, hdc);
466 stream->Release();
469 catch(std::exception&)
471 hr = E_FAIL;
473 return hr;
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)))
480 return E_INVALIDARG;
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);
489 return NOERROR;
492 // IPersist methods
494 HRESULT STDMETHODCALLTYPE CThumbviewer::GetClassID(CLSID* pClassID)
496 pClassID = const_cast<CLSID*>(&CLSID_THUMBVIEWER_HANDLER);
497 return S_OK;
500 // IPersistFile methods
502 HRESULT STDMETHODCALLTYPE CThumbviewer::Load(LPCOLESTR pszFileName, DWORD)
504 filename_ = pszFileName;
505 return S_OK;
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);
526 else
527 result = Gdiplus::Rect(0, 0, src.Width * dest.Height / src.Height, dest.Height);
529 return result;