xref: /AOO41X/main/fpicker/source/win32/filepicker/dibpreview.cxx (revision b557fc96600fce3029f73c89748b6c08fd00b34d)
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