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