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 OS2
28 /************************************************************************
29  * OS/2 surface backend for Apache OpenOffice Cairo Canvas              *
30  ************************************************************************/
31 
32 #define INCL_WIN
33 #include <os2.h>
34 
35 #include <osl/diagnose.h>
36 #include <vcl/bitmap.hxx>
37 #include <vcl/virdev.hxx>
38 #include <vcl/sysdata.hxx>
39 
40 #include "cairo_os2_cairo.hxx"
41 
42 namespace cairo
43 {
44 
45 #include <cairo/cairo-os2.h>
46 
47 // workaround for svpm.h definitions
48 #define sal_Bool BOOL
49 #define PM_FIXED FIXED
50 #define LPGLYPHMETRICS void*
51 #define MAT2 void
52 #include <ft2lib.h>
53 
54     bool IsCairoWorking( OutputDevice* )
55     {
56         // trivially true for OS/2
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     Os2Surface::Os2Surface( 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     Os2Surface::Os2Surface( HWND hwnd, int x, int y, int w, int h) :
87         mpSurface(
88             cairo_os2_surface_create_for_window( hwnd, w + x, h + y),
89             &cairo_surface_destroy)
90     {
91         OSL_TRACE( "Os2Surface::Os2Surface hwnd:%x offset: %d,%d size %d x %d",
92                    hwnd, x, y, w, h);
93         cairo_surface_set_device_offset( mpSurface.get(), 0, 0);
94     }
95 
96     /**
97      * Surface::Surface:   Create platform native Canvas surface from BitmapSystemData
98      * @param pBmpData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
99      *
100      * Create a surface based on image data on pBmpData
101      *
102      * Set the mpSurface to the new surface or NULL
103      **/
104     Os2Surface::Os2Surface( const BitmapSystemData& rBmpData ) :
105         mpSurface()
106     {
107         OSL_TRACE( "Os2Surface::Os2Surface bitmap");
108 #if 0
109         OSL_ASSERT(rBmpData.pDIB == NULL);
110 
111         if(rBmpData.pDIB != NULL) {
112             // So just leave mpSurface to NULL, little else we can do at
113             // this stage. Hopefully the Win32 patch to
114             // cairocanvas::DeviceHelper::getSurface(BitmapSystemData&,
115             // const Size&) will catch the cases where this
116             // constructor would be called with a DIB bitmap, and we
117             // will never get here. At least it worked for Ballmer.ppt.
118         }
119         else
120         {
121             HDC hDC = CreateCompatibleDC(NULL);
122             void* hOrigBitmap;
123             OSL_TRACE ("Surface::Surface(): Selecting bitmap %p into DC %p", rBmpData.pDDB, hDC);
124             hOrigBitmap = SelectObject( hDC, (HANDLE)rBmpData.pDDB );
125             if(hOrigBitmap == NULL)
126                 OSL_TRACE ("SelectObject failed: %d", GetLastError ());
127             mpSurface.reset(
128                 cairo_win32_surface_create(hDC),
129                 &cairo_surface_destroy);
130         }
131 #endif
132 	}
133 
134     /**
135      * Surface::getCairo:  Create Cairo (drawing object) for the Canvas surface
136      *
137      * @return new Cairo or NULL
138      **/
139 	CairoSharedPtr Os2Surface::getCairo() const
140     {
141         return CairoSharedPtr( cairo_create(mpSurface.get()),
142                                &cairo_destroy );
143     }
144 
145     /**
146      * Surface::getSimilar:  Create new similar Canvas surface
147      * @param aContent format of the new surface (cairo_content_t from cairo/src/cairo.h)
148      * @param width width of the new surface
149      * @param height height of the new surface
150      *
151      * Creates a new Canvas surface. This normally creates platform native surface, even though
152      * generic function is used.
153      *
154      * Cairo surface from aContent (cairo_content_t)
155      *
156      * @return new surface or NULL
157      **/
158     SurfaceSharedPtr Os2Surface::getSimilar( Content aContent, int width, int height ) const
159     {
160         OSL_TRACE( "Os2Surface::getSimilar size: %d x %d", width, height);
161         // cairo hits assertion in cairo-surface.c#535 if size is 0x0
162         int w = (width == 0 ? 1 : width);
163         int h = (height == 0 ? 1 : height);
164         return SurfaceSharedPtr(
165             new Os2Surface(
166                 CairoSurfaceSharedPtr(
167                     cairo_surface_create_similar( mpSurface.get(), aContent, w, h),
168                     &cairo_surface_destroy )));
169 	}
170 
171     /**
172      * Surface::Resize:  Resizes the Canvas surface.
173      * @param width new width of the surface
174      * @param height new height of the surface
175      *
176      * Only used on X11.
177      *
178      * @return The new surface or NULL
179      **/
180     void Os2Surface::Resize( int width, int height)
181     {
182         cairo_os2_surface_set_size( mpSurface.get(), width, height, false);
183     }
184 
185     void Os2Surface::flush() const
186     {
187         OSL_TRACE( "Os2Surface::flush");
188         cairo_os2_surface_paint_window( mpSurface.get(), NULL, NULL, 0);
189     }
190 
191     /**
192      * Surface::getDepth:  Get the color depth of the Canvas surface.
193      *
194      * @return color depth
195      **/
196     int Os2Surface::getDepth() const
197     {
198         OSL_TRACE( "Os2Surface::getDepth");
199         if (mpSurface) {
200             switch (cairo_surface_get_content (mpSurface.get())) {
201                 case CAIRO_CONTENT_ALPHA:       return 8;  break;
202                 case CAIRO_CONTENT_COLOR:       return 24; break;
203                 case CAIRO_CONTENT_COLOR_ALPHA: return 32; break;
204             }
205         }
206         OSL_TRACE("Canvas::cairo::Surface::getDepth(): ERROR - depth unspecified!");
207         return -1;
208     }
209 
210 
211     /**
212      * cairo::createVirtualDevice:  Create a VCL virtual device for the CGContext in the cairo Surface
213      *
214      * @return The new virtual device
215      **/
216     boost::shared_ptr<VirtualDevice> Os2Surface::createVirtualDevice() const
217     {
218         SystemGraphicsData aSystemGraphicsData;
219         aSystemGraphicsData.nSize = sizeof(SystemGraphicsData);
220         //aSystemGraphicsData.hDC = cairo_win32_surface_get_dc( mpSurface.get() );
221         OSL_TRACE( "Os2Surface::createVirtualDevice");
222 
223         return boost::shared_ptr<VirtualDevice>(
224                     new VirtualDevice( &aSystemGraphicsData, sal::static_int_cast<USHORT>(getDepth()) ));
225     }
226 
227 
228     /**
229      * cairo::createSurface:     Create generic Canvas surface using given Cairo Surface
230      *
231      * @param rSurface Cairo Surface
232      *
233      * @return new Surface
234      */
235     SurfaceSharedPtr createSurface( const CairoSurfaceSharedPtr& rSurface )
236     {
237         OSL_TRACE( "Os2Surface createSurface from surface");
238         return SurfaceSharedPtr(new Os2Surface(rSurface));
239     }
240 
241 
242     /**
243      * cairo::createSurface:     Create Canvas surface using given VCL Window or Virtualdevice
244      *
245      * @param rSurface Cairo Surface
246      *
247      *  For VCL Window, use platform native system environment data (struct SystemEnvData in vcl/inc/sysdata.hxx)
248      *  For VCL Virtualdevice, use platform native system graphics data (struct SystemGraphicsData in vcl/inc/sysdata.hxx)
249      *
250      * @return new Surface
251      */
252     SurfaceSharedPtr createSurface( const OutputDevice& rRefDevice,
253                                     int x, int y, int width, int height)
254     {
255         SurfaceSharedPtr surf;
256         // cairo hits assertion in cairo-surface.c#535 if size is 0x0
257         int w = (width == 0 ? 1 : width);
258         int h = (height == 0 ? 1 : height);
259         OSL_TRACE( "createSurface refDev:%x, offset: %d x %d", &rRefDevice, x, y);
260 
261         if( rRefDevice.GetOutDevType() == OUTDEV_WINDOW )
262         {
263             OSL_TRACE( "Os2Surface createSurface for WINDOW");
264             const Window &rWindow = (const Window &) rRefDevice;
265             const SystemEnvData* pSysData = GetSysData(&rWindow);
266             if (pSysData && pSysData->hWnd)
267                 surf = SurfaceSharedPtr(new Os2Surface(
268                                             pSysData->hWnd, x, y, w, h));
269         }
270         else if( rRefDevice.GetOutDevType() == OUTDEV_VIRDEV )
271         {
272             OSL_TRACE( "Os2Surface createSurface for VIRDEV");
273             //SystemGraphicsData aSysData = ((const VirtualDevice&) rRefDevice).GetSystemGfxData();
274             //if (aSysData.hDC)
275             //    surf = SurfaceSharedPtr(new Os2Surface((HDC) aSysData.hDC, x, y));
276         }
277         return surf;
278     }
279 
280 
281     /**
282      * cairo::createBitmapSurface:   Create platform native Canvas surface from BitmapSystemData
283      * @param OutputDevice (not used)
284      * @param rData Platform native image data (struct BitmapSystemData in vcl/inc/bitmap.hxx)
285      * @param rSize width and height of the new surface
286      *
287      * Create a surface based on image data on rData
288      *
289      * @return new surface or empty surface
290      **/
291     SurfaceSharedPtr createBitmapSurface( const OutputDevice&     /* rRefDevice */,
292                                           const BitmapSystemData& rData,
293                                           const Size&             rSize )
294     {
295         OSL_TRACE( "createBitmapSurface requested size: %d x %d available size: %d x %d",
296                    rSize.Width(), rSize.Height(), rData.mnWidth, rData.mnHeight );
297 
298         if ( rData.mnWidth == rSize.Width() && rData.mnHeight == rSize.Height() )
299             return SurfaceSharedPtr(new Os2Surface( rData ));
300         else
301             return SurfaceSharedPtr();
302     }
303 
304     typedef USHORT WCHAR;
305     extern "C" ULONG APIENTRY Ft2GetGlyphIndices( HPS, WCHAR *, int, USHORT *, ULONG );
306 
307     /**
308      * cairo::ucs4toindex: Convert ucs4 char to glyph index
309      * @param ucs4 an ucs4 char
310      * @param hfont current font
311      *
312      * @return true if successful
313      **/
314     unsigned long ucs4toindex(unsigned int ucs4, const char* font)
315     {
316         WCHAR unicode[2];
317         USHORT glyph_index;
318         HPS hps = NULL;
319         FATTRS fontAttrs;
320         APIRET rc;
321 
322         hps = WinGetPS( HWND_DESKTOP);
323         if (!hps) return 0;
324 
325         memset( &fontAttrs, 0, sizeof( fontAttrs));
326         fontAttrs.usRecordLength = sizeof( FATTRS);
327         fontAttrs.usCodePage = 850;
328         fontAttrs.fsType = FATTR_TYPE_MBCS;
329         fontAttrs.fsFontUse = FATTR_FONTUSE_NOMIX;
330         strcpy( fontAttrs.szFacename, font);
331         rc = Ft2CreateLogFont( hps, NULL, 1L, &fontAttrs);
332         rc = Ft2SetCharSet( hps, 1L);
333 
334         unicode[0] = ucs4;
335         unicode[1] = 0;
336         if (Ft2GetGlyphIndices( hps, unicode, 1, &glyph_index, 0) == -1) {
337             glyph_index = 0;
338         }
339 
340         WinReleasePS( hps);
341 
342         return glyph_index;
343     }
344 
345 
346 }  // namespace cairo
347 
348 #endif   // OS2
349