1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_canvas.hxx"
30 
31 #ifdef WNT
32 /************************************************************************
33  * Win32 surface backend for OpenOffice.org Cairo Canvas                *
34  ************************************************************************/
35 
36 #include <tools/prewin.h>
37 #include <windows.h>
38 #include <tools/postwin.h>
39 
40 #include <osl/diagnose.h>
41 #include <vcl/bitmap.hxx>
42 #include <vcl/virdev.hxx>
43 #include <vcl/sysdata.hxx>
44 
45 #include "cairo_win32_cairo.hxx"
46 
47 #ifdef CAIRO_HAS_WIN32_SURFACE
48 
49 namespace cairo
50 {
51 
52 #include <cairo-win32.h>
53 
54     bool IsCairoWorking( OutputDevice* )
55     {
56         // trivially true for Windows
57         return true;
58     }
59 
60     /**
61      * Surface::Surface:     Create generic Canvas surface using given Cairo Surface
62      *
63      * @param pSurface Cairo Surface
64      *
65      * This constructor only stores data, it does no processing.
66      * It is used with e.g. cairo_image_surface_create_for_data()
67      * and Surface::getSimilar()
68      *
69      * Set the mpSurface to the new surface or NULL
70      **/
71     Win32Surface::Win32Surface( const CairoSurfaceSharedPtr& pSurface ) :
72         mpSurface( pSurface )
73     {}
74 
75     /**
76      * Surface::Surface:   Create Canvas surface from Window reference.
77      * @param pSysData Platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
78      * @param x horizontal location of the new surface
79      * @param y vertical location of the new surface
80      *
81      * pSysData contains the platform native Window reference.
82      * pSysData is used to create a surface on the Window
83      *
84      * Set the mpSurface to the new surface or NULL
85      **/
86     Win32Surface::Win32Surface( HDC hDC, int x, int y) :
87         mpSurface(
88             cairo_win32_surface_create(hDC),
89             &cairo_surface_destroy)
90     {
91         cairo_surface_set_device_offset( mpSurface.get(), x, y );
92 	}
93 
94     /**
95      * Surface::Surface:   Create platfrom native Canvas surface from BitmapSystemData
96      * @param pBmpData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
97      *
98      * Create a surface based on image data on pBmpData
99      *
100      * Set the mpSurface to the new surface or NULL
101      **/
102     Win32Surface::Win32Surface( const BitmapSystemData& rBmpData ) :
103         mpSurface()
104 	{
105         OSL_ASSERT(rBmpData.pDIB == NULL);
106 
107         if(rBmpData.pDIB != NULL) {
108             // So just leave mpSurface to NULL, little else we can do at
109             // this stage. Hopefully the Win32 patch to
110             // cairocanvas::DeviceHelper::getSurface(BitmapSystemData&,
111             // const Size&) will catch the cases where this
112             // constructor would be called with a DIB bitmap, and we
113             // will never get here. At least it worked for Ballmer.ppt.
114         }
115         else
116         {
117             HDC hDC = CreateCompatibleDC(NULL);
118             void* hOrigBitmap;
119             OSL_TRACE ("Surface::Surface(): Selecting bitmap %p into DC %p", rBmpData.pDDB, hDC);
120             hOrigBitmap = SelectObject( hDC, (HANDLE)rBmpData.pDDB );
121             if(hOrigBitmap == NULL)
122                 OSL_TRACE ("SelectObject failed: %d", GetLastError ());
123             mpSurface.reset(
124                 cairo_win32_surface_create(hDC),
125                 &cairo_surface_destroy);
126         }
127 	}
128 
129     /**
130      * Surface::getCairo:  Create Cairo (drawing object) for the Canvas surface
131      *
132      * @return new Cairo or NULL
133      **/
134 	CairoSharedPtr Win32Surface::getCairo() const
135     {
136         return CairoSharedPtr( cairo_create(mpSurface.get()),
137                                &cairo_destroy );
138     }
139 
140     /**
141      * Surface::getSimilar:  Create new similar Canvas surface
142      * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h)
143      * @param width width of the new surface
144      * @param height height of the new surface
145      *
146      * Creates a new Canvas surface. This normally creates platform native surface, even though
147      * generic function is used.
148      *
149      * Cairo surface from aContent (cairo_content_t)
150      *
151      * @return new surface or NULL
152      **/
153 	SurfaceSharedPtr Win32Surface::getSimilar( Content aContent, int width, int height ) const
154 	{
155         return SurfaceSharedPtr(
156             new Win32Surface(
157                 CairoSurfaceSharedPtr(
158                     cairo_surface_create_similar( mpSurface.get(), aContent, width, height ),
159                     &cairo_surface_destroy )));
160 	}
161 
162     /**
163      * Surface::Resize:  Resizes the Canvas surface.
164      * @param width new width of the surface
165      * @param height new height of the surface
166      *
167      * Only used on X11.
168      *
169      * @return The new surface or NULL
170      **/
171 	void Win32Surface::Resize( int /*width*/, int /*height*/ )
172 	{
173         OSL_ENSURE(false,"not supposed to be called!");
174 	}
175 
176     void Win32Surface::flush() const
177     {
178         GdiFlush();
179     }
180 
181     /**
182      * Surface::getDepth:  Get the color depth of the Canvas surface.
183      *
184      * @return color depth
185      **/
186 	int Win32Surface::getDepth() const
187 	{
188         if (mpSurface) {
189             switch (cairo_surface_get_content (mpSurface.get())) {
190                 case CAIRO_CONTENT_ALPHA:       return 8;  break;
191                 case CAIRO_CONTENT_COLOR:       return 24; break;
192                 case CAIRO_CONTENT_COLOR_ALPHA: return 32; break;
193             }
194         }
195         OSL_TRACE("Canvas::cairo::Surface::getDepth(): ERROR - depth unspecified!");
196 		return -1;
197 	}
198 
199 
200     /**
201      * cairo::createVirtualDevice:  Create a VCL virtual device for the CGContext in the cairo Surface
202      *
203      * @return The new virtual device
204      **/
205     boost::shared_ptr<VirtualDevice> Win32Surface::createVirtualDevice() const
206     {
207 		SystemGraphicsData aSystemGraphicsData;
208 		aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
209         aSystemGraphicsData.hDC = cairo_win32_surface_get_dc( mpSurface.get() );
210 
211 		return boost::shared_ptr<VirtualDevice>(
212             new VirtualDevice( &aSystemGraphicsData, sal::static_int_cast<USHORT>(getDepth()) ));
213     }
214 
215 
216     /**
217      * cairo::createSurface:     Create generic Canvas surface using given Cairo Surface
218      *
219      * @param rSurface Cairo Surface
220      *
221      * @return new Surface
222      */
223     SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface )
224     {
225         return SurfaceSharedPtr(new Win32Surface(rSurface));
226     }
227 
228 
229     /**
230      * cairo::createSurface:     Create Canvas surface using given VCL Window or Virtualdevice
231      *
232      * @param rSurface Cairo Surface
233      *
234      *  For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
235      *  For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx)
236      *
237      * @return new Surface
238      */
239     SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice,
240                                     int x, int y, int /* width */, int /* height */)
241     {
242         SurfaceSharedPtr surf;
243 
244         if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
245         {
246             const Window &rWindow = (const Window &) rRefDevice;
247             const SystemEnvData* pSysData = GetSysData(&rWindow);
248             if (pSysData && pSysData->hWnd)
249                 surf = SurfaceSharedPtr(new Win32Surface(GetDC((HWND) pSysData->hWnd), x, y));
250         }
251         else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
252         {
253             SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData();
254             if (aSysData.hDC)
255                 surf = SurfaceSharedPtr(new Win32Surface((HDC) aSysData.hDC, x, y));
256         }
257         return surf;
258     }
259 
260 
261     /**
262      * cairo::createBitmapSurface:   Create platfrom native Canvas surface from BitmapSystemData
263      * @param OutputDevice (not used)
264      * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
265      * @param rSize width and height of the new surface
266      *
267      * Create a surface based on image data on rData
268      *
269      * @return new surface or empty surface
270      **/
271     SurfaceSharedPtr createBitmapSurface( const OutputDevice&     /* rRefDevice */,
272                                           const BitmapSystemData& rData,
273                                           const Size&             rSize )
274     {
275         OSL_TRACE( "requested size: %d x %d available size: %d x %d",
276                    rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight );
277 
278         if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
279             return SurfaceSharedPtr(new Win32Surface( rData ));
280         else
281             return SurfaceSharedPtr();
282     }
283 
284 
285     /**
286      * cairo::ucs4toindex: Convert ucs4 char to glyph index
287      * @param ucs4 an ucs4 char
288      * @param hfont current font
289      *
290      * @return true if successful
291      **/
292     unsigned long ucs4toindex(unsigned int ucs4, HFONT hfont)
293     {
294         wchar_t unicode[2];
295         WORD glyph_index;
296         HDC hdc = NULL;
297         int i = 0;
298 
299         hdc = CreateCompatibleDC (NULL);
300 
301         if (!hdc) return 0;
302         if (!SetGraphicsMode (hdc, GM_ADVANCED)) {
303             DeleteDC (hdc);
304             return 0;
305         }
306 
307         SelectObject (hdc, hfont);
308         SetMapMode (hdc, MM_TEXT);
309 
310         unicode[0] = ucs4;
311         unicode[1] = 0;
312         if (GetGlyphIndicesW (hdc, unicode, 1, &glyph_index, 0) == GDI_ERROR) {
313             glyph_index = 0;
314         }
315 
316         DeleteDC (hdc);
317         return glyph_index;
318 	}
319 
320 
321 }  // namespace cairo
322 
323 #endif   // CAIRO_HAS_WIN32_SURFACE
324 
325 #endif   // WNT
326