1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_fpicker.hxx"
26 
27 //------------------------------------------------------------------------
28 // includes
29 //------------------------------------------------------------------------
30 
31 #include <tchar.h>
32 #include "dibpreview.hxx"
33 #include <osl/diagnose.h>
34 
35 #ifndef _COM_SUN_STAR_UI_DIALOG_FILEPREVIEWIMAGEFORMATS_HPP_
36 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
37 #endif
38 
39 #ifndef _USTRING_HXX_
40 #include <rtl/ustring.hxx>
41 #endif
42 
43 #include <stdexcept>
44 #include <string>
45 
46 //------------------------------------------------------------------------
47 //
48 //------------------------------------------------------------------------
49 
50 using ::com::sun::star::uno::Sequence;
51 using ::com::sun::star::uno::RuntimeException;
52 using ::com::sun::star::uno::Any;
53 using ::com::sun::star::lang::IllegalArgumentException;
54 using rtl::OUString;
55 
56 //------------------------------------------------------------------------
57 //
58 //------------------------------------------------------------------------
59 
60 namespace /* private */
61 {
62     const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst");
63 };
64 
65 //------------------------------------------------------------------------
66 // defines
67 //------------------------------------------------------------------------
68 
69 #define PREVIEWWND_CLASS_NAME TEXT("DIBPreviewWnd###")
70 
71 // means 3 pixel left and 3 pixel right
72 #define HORZ_BODER_SPACE    6
73 
74 // means 3 pixel top and 3 pixel bottom
75 #define VERT_BORDER_SPACE   6
76 
77 //---------------------------------------------------
78 // static member initialization
79 //---------------------------------------------------
80 
81 osl::Mutex CDIBPreview::s_Mutex;
82 ATOM CDIBPreview::s_ClassAtom = 0;
83 sal_Int32 CDIBPreview::s_RegisterDibPreviewWndCount = 0;
84 
85 //---------------------------------------------------
86 //
87 //---------------------------------------------------
88 
CDIBPreview(HINSTANCE instance,HWND parent,sal_Bool bShowWindow)89 CDIBPreview::CDIBPreview(HINSTANCE instance,HWND parent,sal_Bool bShowWindow) :
90 	m_Instance(instance)
91 {
92 	RegisterDibPreviewWindowClass();
93 
94 	DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
95 
96 	if (bShowWindow)
97 		dwStyle |= WS_VISIBLE;
98 
99 	m_Hwnd = CreateWindowEx(
100 		WS_EX_CLIENTEDGE,
101 		PREVIEWWND_CLASS_NAME,
102 		TEXT(""),
103 		dwStyle,
104 		0, 0, 0, 0,
105         parent,
106 		(HMENU)0x0, // for child windows this will
107 					// be used as child window identifier
108 		m_Instance,
109         (LPVOID)this // pass a pointer to the current
110                      // instance of this class
111     );
112 
113 	bool bSuccess = IsWindow(m_Hwnd);
114 
115 	OSL_POSTCOND(bSuccess,"Coud not create preview window");
116 
117 	if (!bSuccess)
118 	{
119 		UnregisterDibPreviewWindowClass();
120 		throw std::runtime_error("Could not create preview window");
121 	}
122 }
123 
124 //---------------------------------------------------
125 //
126 //---------------------------------------------------
127 
~CDIBPreview()128 CDIBPreview::~CDIBPreview( )
129 {
130     // remember: we don't have to destroy the
131     // preview window because it will be destroyed
132     // by it's parent window (the FileOpen dialog)
133     // but we have to unregister the window class
134     //if ( m_bWndClassRegistered )
135     UnregisterDibPreviewWindowClass();
136 }
137 
138 //-------------------------------
139 //
140 //-------------------------------
141 
getTargetColorDepth()142 sal_Int32 SAL_CALL CDIBPreview::getTargetColorDepth() throw (RuntimeException)
143 {
144 	HDC hdc = GetDC(m_Hwnd);
145     int clrRes = 0;
146 
147     if (hdc)
148         clrRes = GetDeviceCaps(hdc, COLORRES);
149 
150     return clrRes;
151 }
152 
153 //-------------------------------
154 //
155 //-------------------------------
156 
getAvailableWidth()157 sal_Int32 SAL_CALL CDIBPreview::getAvailableWidth() throw (RuntimeException)
158 {
159 	RECT rect;
160 	bool bRet = GetClientRect(m_Hwnd,&rect);
161 
162 	sal_Int32 cx = 0;
163 
164     if ( bRet )
165         cx = rect.right;
166 
167 	return cx;
168 }
169 
170 //-------------------------------
171 //
172 //-------------------------------
173 
getAvailableHeight()174 sal_Int32 SAL_CALL CDIBPreview::getAvailableHeight() throw (RuntimeException)
175 {
176 	RECT rect;
177 	bool bRet = GetClientRect(m_Hwnd,&rect);
178 
179 	sal_Int32 cy = 0;
180 
181     if ( bRet )
182         cy = rect.bottom;
183 
184 	return cy;
185 }
186 
187 //-------------------------------
188 //
189 //-------------------------------
190 
setImage(sal_Int16 aImageFormat,const Any & aImage)191 void SAL_CALL CDIBPreview::setImage(sal_Int16 aImageFormat, const Any& aImage)
192 	throw (IllegalArgumentException, RuntimeException)
193 {
194 	PreviewBase::setImage(aImageFormat,aImage);
195 
196 	// if the any has no value we have an
197 	// empty Sequence which clears the
198 	// preview window
199 	osl::ClearableMutexGuard aGuard(m_PaintLock);
200 
201 	m_Image.realloc(0);
202 	m_ImageData >>= m_Image;
203 
204 	aGuard.clear();
205 
206 	InvalidateRect(m_Hwnd,NULL,sal_False);
207 	UpdateWindow(m_Hwnd);
208 }
209 
210 //-------------------------------
211 //
212 //-------------------------------
213 
setShowState(sal_Bool bShowState)214 sal_Bool SAL_CALL CDIBPreview::setShowState(sal_Bool bShowState) throw (RuntimeException)
215 {
216 	PreviewBase::setShowState(bShowState);
217 	ShowWindow(m_Hwnd, m_bShowState ? SW_SHOW : SW_HIDE);
218     return sal_True;
219 }
220 
221 //-------------------------------
222 //
223 //-------------------------------
224 
getShowState()225 sal_Bool SAL_CALL CDIBPreview::getShowState() throw (RuntimeException)
226 {
227 	return (sal_Bool)IsWindowVisible(m_Hwnd);
228 }
229 
230 //-------------------------------
231 //
232 //-------------------------------
233 
getWindowHandle() const234 HWND SAL_CALL CDIBPreview::getWindowHandle() const
235 {
236 	return m_Hwnd;
237 }
238 
239 //---------------------------------------------------
240 //
241 //---------------------------------------------------
242 
onPaint(HWND hWnd,HDC hDC)243 void SAL_CALL CDIBPreview::onPaint(HWND hWnd, HDC hDC)
244 {
245 	BITMAPFILEHEADER*  pbmfh;
246     BITMAPINFO      *  pbmi;
247     sal_uInt8            *  pBits;
248     int                cxDib;
249     int                cyDib;
250 
251 	osl::MutexGuard aGuard(m_PaintLock);
252 
253 	try
254 	{
255 		pbmfh = reinterpret_cast<BITMAPFILEHEADER*>(m_Image.getArray());
256 
257 		if ( !IsBadReadPtr( pbmfh, sizeof(BITMAPFILEHEADER)) &&
258 			 (pbmfh->bfType == ('B' | ('M' << 8))) )
259 		{
260 			pbmi  = reinterpret_cast<BITMAPINFO*>((pbmfh + 1));
261 			pBits = reinterpret_cast<sal_uInt8*>(((DWORD)pbmfh) + pbmfh->bfOffBits);
262 
263 			cxDib =      pbmi->bmiHeader.biWidth;
264 			cyDib = abs (pbmi->bmiHeader.biHeight);
265 
266 			SetStretchBltMode(hDC, COLORONCOLOR);
267 
268 			int nWidth  = getAvailableWidth();
269 			int nHeight = getAvailableHeight();
270 
271 			int nX = abs(nWidth - cxDib) / 2;
272 			int nY = abs(nHeight - cyDib) / 2;
273 
274 			int GDIError = GDI_ERROR;
275             GDIError = StretchDIBits(
276 				hDC, nX, nY, cxDib, cyDib,
277 				0, 0, cxDib, cyDib, pBits, pbmi,
278 				DIB_RGB_COLORS, SRCCOPY);
279 
280             OSL_ASSERT(GDI_ERROR != GDIError);
281 
282 			// paint the border
283 			RECT rc;
284 
285 			if (nY > 0)
286 			{
287 				// top
288 				rc.left	  = 0;
289 				rc.top	  = 0;
290 				rc.right  = nWidth;
291 				rc.bottom = nY;
292 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
293 
294 				// bottom
295 				rc.left	  = 0;
296 				rc.top	  = nHeight - nY - 1;
297 				rc.right  = nWidth;
298 				rc.bottom = nHeight;
299 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
300 			}
301 
302 			if (nX > 0)
303 			{
304 				// left
305 				rc.left	  = 0;
306 				rc.top	  = nY;
307 				rc.right  = nX;
308 				rc.bottom = nHeight - nY;
309 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
310 
311 				// right
312 				rc.left	  = nWidth - nX - 1;
313 				rc.top	  = nY;
314 				rc.right  = nWidth;
315 				rc.bottom = nHeight - nY;
316 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
317 			}
318 		}
319 		else // clear background
320 		{
321 			RECT rc;
322 			GetClientRect(hWnd,&rc);
323 			FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
324 		}
325 	}
326 	catch(...)
327 	{
328 		OSL_ASSERT(sal_False);
329 	}
330 }
331 
332 //---------------------------------------------------
333 //
334 //---------------------------------------------------
335 
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)336 LRESULT CALLBACK CDIBPreview::WndProc(
337     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
338 {
339 	LRESULT lResult = 0;
340 
341 	switch(uMsg)
342 	{
343 
344     // we connect a pointer to the current instance
345     // with a window instance via SetProp
346     case WM_CREATE:
347         {
348             LPCREATESTRUCT lpcs =
349                 reinterpret_cast< LPCREATESTRUCT >(lParam);
350 
351             OSL_ASSERT(lpcs->lpCreateParams);
352 
353             // connect the instance handle to the window
354             SetProp(hWnd, CURRENT_INSTANCE, lpcs->lpCreateParams);
355         }
356         break;
357 
358     // we remove the window property which connects
359     // a class instance with a window class
360     case WM_NCDESTROY:
361         {
362             // RemoveProp returns the saved value on success
363             if (reinterpret_cast<CDIBPreview*>(
364                     RemoveProp(hWnd, CURRENT_INSTANCE)) == NULL)
365             {
366                 OSL_ASSERT(false);
367             }
368         }
369         break;
370 
371 	case WM_PAINT:
372 	{
373 		CDIBPreview* pImpl = reinterpret_cast<CDIBPreview*>(
374             GetProp(hWnd, CURRENT_INSTANCE));
375 
376         OSL_ASSERT(pImpl);
377 
378 		HDC         hDC;
379 		PAINTSTRUCT ps;
380 
381 		hDC = BeginPaint(hWnd,&ps);
382 		pImpl->onPaint(hWnd,hDC);
383 		EndPaint(hWnd,&ps);
384 	}
385 	break;
386 
387 	// ignore this message in order to
388 	// avoid flickering during paint
389 	case WM_ERASEBKGND:
390 		lResult = 1;
391 		break;
392 
393 	default:
394 		return DefWindowProc(hWnd, uMsg, wParam, lParam);
395 	}
396 
397 	return lResult;
398 }
399 
400 //---------------------------------------------------
401 //
402 //---------------------------------------------------
403 
RegisterDibPreviewWindowClass()404 ATOM SAL_CALL CDIBPreview::RegisterDibPreviewWindowClass()
405 {
406     osl::MutexGuard aGuard( s_Mutex );
407 
408     if (0 == s_ClassAtom)
409     {
410         // register the preview window class
411 	    WNDCLASSEX wndClsEx;
412 	    ZeroMemory(&wndClsEx, sizeof(wndClsEx));
413 
414 	    wndClsEx.cbSize        = sizeof(wndClsEx);
415 	    wndClsEx.style		   = CS_HREDRAW | CS_VREDRAW;
416 	    wndClsEx.lpfnWndProc   = CDIBPreview::WndProc;
417 	    wndClsEx.hInstance     = m_Instance;
418 	    wndClsEx.hbrBackground = (HBRUSH)(COLOR_INACTIVEBORDER + 1);
419 	    wndClsEx.lpszClassName = PREVIEWWND_CLASS_NAME;
420 
421 	    // register the preview window class
422 	    // !!! Win95 -   the window class will be unregistered automaticly
423 	    //			     if the dll is unloaded
424 	    //     Win2000 - the window class must be unregistered manually
425 	    //				 if the dll is unloaded
426 	    s_ClassAtom = RegisterClassEx(&wndClsEx);
427 
428 		OSL_POSTCOND(s_ClassAtom,"Could  not register preview window class");
429 
430 		if (0 == s_ClassAtom)
431 			throw std::runtime_error("Preview window class could not be registered");
432     }
433 
434     // increment the register class counter
435     // so that we keep track of the number
436     // of class registrations
437     //if ( 0 != s_ClassAtom )
438     s_RegisterDibPreviewWndCount++;
439 
440     return s_ClassAtom;
441 }
442 
443 //---------------------------------------------------
444 //
445 //---------------------------------------------------
446 
UnregisterDibPreviewWindowClass()447 void SAL_CALL CDIBPreview::UnregisterDibPreviewWindowClass()
448 {
449     osl::MutexGuard aGuard( s_Mutex );
450 
451     OSL_ASSERT( ( (0 != s_ClassAtom) && (s_RegisterDibPreviewWndCount > 0)) ||
452                 ( (0 == s_ClassAtom) && (0 == s_RegisterDibPreviewWndCount) ) );
453 
454     // update the register class counter
455     // and unregister the window class if
456     // counter drops to zero
457     if (0 != s_ClassAtom)
458     {
459         s_RegisterDibPreviewWndCount--;
460         OSL_ASSERT(s_RegisterDibPreviewWndCount >= 0);
461     }
462 
463     if (0 == s_RegisterDibPreviewWndCount)
464     {
465         UnregisterClass((LPCTSTR)MAKELONG(s_ClassAtom,0),m_Instance);
466         s_ClassAtom = 0;
467     }
468 }
469