credui: Delete the static critical section when unloading the dll.
[wine] / dlls / gdi32 / mapping.c
1 /*
2  * GDI mapping mode functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdarg.h>
22
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "gdi_private.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(dc);
30
31
32 /***********************************************************************
33  *           MAPPING_FixIsotropic
34  *
35  * Fix viewport extensions for isotropic mode.
36  */
37 static void MAPPING_FixIsotropic( DC * dc )
38 {
39     double xdim = fabs((double)dc->vportExtX * dc->virtual_size.cx /
40                   (dc->virtual_res.cx * dc->wndExtX));
41     double ydim = fabs((double)dc->vportExtY * dc->virtual_size.cy /
42                   (dc->virtual_res.cy * dc->wndExtY));
43
44     if (xdim > ydim)
45     {
46         INT mincx = (dc->vportExtX >= 0) ? 1 : -1;
47         dc->vportExtX = floor(dc->vportExtX * ydim / xdim + 0.5);
48         if (!dc->vportExtX) dc->vportExtX = mincx;
49     }
50     else
51     {
52         INT mincy = (dc->vportExtY >= 0) ? 1 : -1;
53         dc->vportExtY = floor(dc->vportExtY * xdim / ydim + 0.5);
54         if (!dc->vportExtY) dc->vportExtY = mincy;
55     }
56 }
57
58
59 /***********************************************************************
60  *           null driver fallback implementations
61  */
62
63 BOOL nulldrv_OffsetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
64 {
65     DC *dc = get_nulldrv_dc( dev );
66
67     if (pt)
68     {
69         pt->x = dc->vportOrgX;
70         pt->y = dc->vportOrgY;
71     }
72     dc->vportOrgX += x;
73     dc->vportOrgY += y;
74     DC_UpdateXforms( dc );
75     return TRUE;
76 }
77
78 BOOL nulldrv_OffsetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
79 {
80     DC *dc = get_nulldrv_dc( dev );
81
82     if (pt)
83     {
84         pt->x = dc->wndOrgX;
85         pt->y = dc->wndOrgY;
86     }
87     dc->wndOrgX += x;
88     dc->wndOrgY += y;
89     DC_UpdateXforms( dc );
90     return TRUE;
91 }
92
93 BOOL nulldrv_ScaleViewportExtEx( PHYSDEV dev, INT x_num, INT x_denom, INT y_num, INT y_denom, SIZE *size )
94 {
95     DC *dc = get_nulldrv_dc( dev );
96
97     if (size)
98     {
99         size->cx = dc->vportExtX;
100         size->cy = dc->vportExtY;
101     }
102     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
103     if (!x_num || !x_denom || !y_num || !y_denom) return FALSE;
104
105     dc->vportExtX = (dc->vportExtX * x_num) / x_denom;
106     dc->vportExtY = (dc->vportExtY * y_num) / y_denom;
107     if (dc->vportExtX == 0) dc->vportExtX = 1;
108     if (dc->vportExtY == 0) dc->vportExtY = 1;
109     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
110     DC_UpdateXforms( dc );
111     return TRUE;
112 }
113
114 BOOL nulldrv_ScaleWindowExtEx( PHYSDEV dev, INT x_num, INT x_denom, INT y_num, INT y_denom, SIZE *size )
115 {
116     DC *dc = get_nulldrv_dc( dev );
117
118     if (size)
119     {
120         size->cx = dc->wndExtX;
121         size->cy = dc->wndExtY;
122     }
123     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
124     if (!x_num || !x_denom || !y_num || !y_denom) return FALSE;
125
126     dc->wndExtX = (dc->wndExtX * x_num) / x_denom;
127     dc->wndExtY = (dc->wndExtY * y_num) / y_denom;
128     if (dc->wndExtX == 0) dc->wndExtX = 1;
129     if (dc->wndExtY == 0) dc->wndExtY = 1;
130     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
131     DC_UpdateXforms( dc );
132     return TRUE;
133 }
134
135 INT nulldrv_SetMapMode( PHYSDEV dev, INT mode )
136 {
137     DC *dc = get_nulldrv_dc( dev );
138     INT ret = dc->MapMode;
139     INT horzSize, vertSize, horzRes, vertRes;
140
141     if (mode == dc->MapMode && (mode == MM_ISOTROPIC || mode == MM_ANISOTROPIC)) return ret;
142
143     horzSize = dc->virtual_size.cx;
144     vertSize = dc->virtual_size.cy;
145     horzRes  = dc->virtual_res.cx;
146     vertRes  = dc->virtual_res.cy;
147     switch (mode)
148     {
149     case MM_TEXT:
150         dc->wndExtX   = 1;
151         dc->wndExtY   = 1;
152         dc->vportExtX = 1;
153         dc->vportExtY = 1;
154         break;
155     case MM_LOMETRIC:
156     case MM_ISOTROPIC:
157         dc->wndExtX   = horzSize * 10;
158         dc->wndExtY   = vertSize * 10;
159         dc->vportExtX = horzRes;
160         dc->vportExtY = -vertRes;
161         break;
162     case MM_HIMETRIC:
163         dc->wndExtX   = horzSize * 100;
164         dc->wndExtY   = vertSize * 100;
165         dc->vportExtX = horzRes;
166         dc->vportExtY = -vertRes;
167         break;
168     case MM_LOENGLISH:
169         dc->wndExtX   = MulDiv(1000, horzSize, 254);
170         dc->wndExtY   = MulDiv(1000, vertSize, 254);
171         dc->vportExtX = horzRes;
172         dc->vportExtY = -vertRes;
173         break;
174     case MM_HIENGLISH:
175         dc->wndExtX   = MulDiv(10000, horzSize, 254);
176         dc->wndExtY   = MulDiv(10000, vertSize, 254);
177         dc->vportExtX = horzRes;
178         dc->vportExtY = -vertRes;
179         break;
180     case MM_TWIPS:
181         dc->wndExtX   = MulDiv(14400, horzSize, 254);
182         dc->wndExtY   = MulDiv(14400, vertSize, 254);
183         dc->vportExtX = horzRes;
184         dc->vportExtY = -vertRes;
185         break;
186     case MM_ANISOTROPIC:
187         break;
188     default:
189         return 0;
190     }
191     /* RTL layout is always MM_ANISOTROPIC */
192     if (!(dc->layout & LAYOUT_RTL)) dc->MapMode = mode;
193     DC_UpdateXforms( dc );
194     return ret;
195 }
196
197 BOOL nulldrv_SetViewportExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
198 {
199     DC *dc = get_nulldrv_dc( dev );
200
201     if (size)
202     {
203         size->cx = dc->vportExtX;
204         size->cy = dc->vportExtY;
205     }
206     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
207     if (!cx || !cy) return FALSE;
208     dc->vportExtX = cx;
209     dc->vportExtY = cy;
210     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
211     DC_UpdateXforms( dc );
212     return TRUE;
213 }
214
215 BOOL nulldrv_SetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
216 {
217     DC *dc = get_nulldrv_dc( dev );
218
219     if (pt)
220     {
221         pt->x = dc->vportOrgX;
222         pt->y = dc->vportOrgY;
223     }
224     dc->vportOrgX = x;
225     dc->vportOrgY = y;
226     DC_UpdateXforms( dc );
227     return TRUE;
228 }
229
230 BOOL nulldrv_SetWindowExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
231 {
232     DC *dc = get_nulldrv_dc( dev );
233
234     if (size)
235     {
236         size->cx = dc->wndExtX;
237         size->cy = dc->wndExtY;
238     }
239     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
240     if (!cx || !cy) return FALSE;
241     dc->wndExtX = cx;
242     dc->wndExtY = cy;
243     /* The API docs say that you should call SetWindowExtEx before
244        SetViewportExtEx. This advice does not imply that Windows
245        doesn't ensure the isotropic mapping after SetWindowExtEx! */
246     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
247     DC_UpdateXforms( dc );
248     return TRUE;
249 }
250
251 BOOL nulldrv_SetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
252 {
253     DC *dc = get_nulldrv_dc( dev );
254
255     if (pt)
256     {
257         pt->x = dc->wndOrgX;
258         pt->y = dc->wndOrgY;
259     }
260     dc->wndOrgX = x;
261     dc->wndOrgY = y;
262     DC_UpdateXforms( dc );
263     return TRUE;
264 }
265
266 BOOL nulldrv_ModifyWorldTransform( PHYSDEV dev, const XFORM *xform, DWORD mode )
267 {
268     DC *dc = get_nulldrv_dc( dev );
269
270     switch (mode)
271     {
272     case MWT_IDENTITY:
273         dc->xformWorld2Wnd.eM11 = 1.0f;
274         dc->xformWorld2Wnd.eM12 = 0.0f;
275         dc->xformWorld2Wnd.eM21 = 0.0f;
276         dc->xformWorld2Wnd.eM22 = 1.0f;
277         dc->xformWorld2Wnd.eDx  = 0.0f;
278         dc->xformWorld2Wnd.eDy  = 0.0f;
279         break;
280     case MWT_LEFTMULTIPLY:
281         CombineTransform( &dc->xformWorld2Wnd, xform, &dc->xformWorld2Wnd );
282         break;
283     case MWT_RIGHTMULTIPLY:
284         CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd, xform );
285         break;
286     default:
287         return FALSE;
288     }
289     DC_UpdateXforms( dc );
290     return TRUE;
291 }
292
293 BOOL nulldrv_SetWorldTransform( PHYSDEV dev, const XFORM *xform )
294 {
295     DC *dc = get_nulldrv_dc( dev );
296
297     dc->xformWorld2Wnd = *xform;
298     DC_UpdateXforms( dc );
299     return TRUE;
300 }
301
302 /***********************************************************************
303  *           DPtoLP    (GDI32.@)
304  */
305 BOOL WINAPI DPtoLP( HDC hdc, LPPOINT points, INT count )
306 {
307     DC * dc = get_dc_ptr( hdc );
308     if (!dc) return FALSE;
309
310     if (dc->vport2WorldValid)
311     {
312         while (count--)
313         {
314             double x = points->x;
315             double y = points->y;
316             points->x = floor( x * dc->xformVport2World.eM11 +
317                                y * dc->xformVport2World.eM21 +
318                                dc->xformVport2World.eDx + 0.5 );
319             points->y = floor( x * dc->xformVport2World.eM12 +
320                                y * dc->xformVport2World.eM22 +
321                                dc->xformVport2World.eDy + 0.5 );
322             points++;
323         }
324     }
325     release_dc_ptr( dc );
326     return (count < 0);
327 }
328
329
330 /***********************************************************************
331  *           LPtoDP    (GDI32.@)
332  */
333 BOOL WINAPI LPtoDP( HDC hdc, LPPOINT points, INT count )
334 {
335     DC * dc = get_dc_ptr( hdc );
336     if (!dc) return FALSE;
337
338     while (count--)
339     {
340         double x = points->x;
341         double y = points->y;
342         points->x = floor( x * dc->xformWorld2Vport.eM11 +
343                            y * dc->xformWorld2Vport.eM21 +
344                            dc->xformWorld2Vport.eDx + 0.5 );
345         points->y = floor( x * dc->xformWorld2Vport.eM12 +
346                            y * dc->xformWorld2Vport.eM22 +
347                            dc->xformWorld2Vport.eDy + 0.5 );
348         points++;
349     }
350     release_dc_ptr( dc );
351     return TRUE;
352 }
353
354
355 /***********************************************************************
356  *           SetMapMode    (GDI32.@)
357  */
358 INT WINAPI SetMapMode( HDC hdc, INT mode )
359 {
360     INT ret = 0;
361     DC * dc = get_dc_ptr( hdc );
362
363     TRACE("%p %d\n", hdc, mode );
364
365     if (dc)
366     {
367         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapMode );
368         ret = physdev->funcs->pSetMapMode( physdev, mode );
369         release_dc_ptr( dc );
370     }
371     return ret;
372 }
373
374
375 /***********************************************************************
376  *           SetViewportExtEx    (GDI32.@)
377  */
378 BOOL WINAPI SetViewportExtEx( HDC hdc, INT x, INT y, LPSIZE size )
379 {
380     INT ret = FALSE;
381     DC * dc = get_dc_ptr( hdc );
382
383     if (dc)
384     {
385         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetViewportExtEx );
386         ret = physdev->funcs->pSetViewportExtEx( physdev, x, y, size );
387         release_dc_ptr( dc );
388     }
389     return ret;
390 }
391
392
393 /***********************************************************************
394  *           SetViewportOrgEx    (GDI32.@)
395  */
396 BOOL WINAPI SetViewportOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
397 {
398     INT ret = FALSE;
399     DC * dc = get_dc_ptr( hdc );
400
401     if (dc)
402     {
403         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetViewportOrgEx );
404         ret = physdev->funcs->pSetViewportOrgEx( physdev, x, y, pt );
405         release_dc_ptr( dc );
406     }
407     return ret;
408 }
409
410
411 /***********************************************************************
412  *           SetWindowExtEx    (GDI32.@)
413  */
414 BOOL WINAPI SetWindowExtEx( HDC hdc, INT x, INT y, LPSIZE size )
415 {
416     INT ret = FALSE;
417     DC * dc = get_dc_ptr( hdc );
418
419     if (dc)
420     {
421         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetWindowExtEx );
422         ret = physdev->funcs->pSetWindowExtEx( physdev, x, y, size );
423         release_dc_ptr( dc );
424     }
425     return ret;
426 }
427
428
429 /***********************************************************************
430  *           SetWindowOrgEx    (GDI32.@)
431  */
432 BOOL WINAPI SetWindowOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
433 {
434     INT ret = FALSE;
435     DC * dc = get_dc_ptr( hdc );
436
437     if (dc)
438     {
439         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetWindowOrgEx );
440         ret = physdev->funcs->pSetWindowOrgEx( physdev, x, y, pt );
441         release_dc_ptr( dc );
442     }
443     return ret;
444 }
445
446
447 /***********************************************************************
448  *           OffsetViewportOrgEx    (GDI32.@)
449  */
450 BOOL WINAPI OffsetViewportOrgEx( HDC hdc, INT x, INT y, LPPOINT pt)
451 {
452     INT ret = FALSE;
453     DC * dc = get_dc_ptr( hdc );
454
455     if (dc)
456     {
457         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pOffsetViewportOrgEx );
458         ret = physdev->funcs->pOffsetViewportOrgEx( physdev, x, y, pt );
459         release_dc_ptr( dc );
460     }
461     return ret;
462 }
463
464
465 /***********************************************************************
466  *           OffsetWindowOrgEx    (GDI32.@)
467  */
468 BOOL WINAPI OffsetWindowOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
469 {
470     INT ret = FALSE;
471     DC * dc = get_dc_ptr( hdc );
472
473     if (dc)
474     {
475         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pOffsetWindowOrgEx );
476         ret = physdev->funcs->pOffsetWindowOrgEx( physdev, x, y, pt );
477         release_dc_ptr( dc );
478     }
479     return ret;
480 }
481
482
483 /***********************************************************************
484  *           ScaleViewportExtEx    (GDI32.@)
485  */
486 BOOL WINAPI ScaleViewportExtEx( HDC hdc, INT xNum, INT xDenom,
487                                     INT yNum, INT yDenom, LPSIZE size )
488 {
489     INT ret = FALSE;
490     DC * dc = get_dc_ptr( hdc );
491
492     if (dc)
493     {
494         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pScaleViewportExtEx );
495         ret = physdev->funcs->pScaleViewportExtEx( physdev, xNum, xDenom, yNum, yDenom, size );
496         release_dc_ptr( dc );
497     }
498     return ret;
499 }
500
501
502 /***********************************************************************
503  *           ScaleWindowExtEx    (GDI32.@)
504  */
505 BOOL WINAPI ScaleWindowExtEx( HDC hdc, INT xNum, INT xDenom,
506                                   INT yNum, INT yDenom, LPSIZE size )
507 {
508     INT ret = FALSE;
509     DC * dc = get_dc_ptr( hdc );
510
511     if (dc)
512     {
513         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pScaleWindowExtEx );
514         ret = physdev->funcs->pScaleWindowExtEx( physdev, xNum, xDenom, yNum, yDenom, size );
515         release_dc_ptr( dc );
516     }
517     return ret;
518 }
519
520
521 /****************************************************************************
522  *           ModifyWorldTransform   (GDI32.@)
523  */
524 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform, DWORD mode )
525 {
526     BOOL ret = FALSE;
527     DC *dc;
528
529     if (!xform && mode != MWT_IDENTITY) return FALSE;
530     if ((dc = get_dc_ptr( hdc )))
531     {
532         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pModifyWorldTransform );
533         if (dc->GraphicsMode == GM_ADVANCED)
534             ret = physdev->funcs->pModifyWorldTransform( physdev, xform, mode );
535         release_dc_ptr( dc );
536     }
537     return ret;
538 }
539
540
541 /***********************************************************************
542  *           SetWorldTransform    (GDI32.@)
543  */
544 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
545 {
546     BOOL ret = FALSE;
547     DC *dc;
548
549     if (!xform) return FALSE;
550     /* The transform must conform to (eM11 * eM22 != eM12 * eM21) requirement */
551     if (xform->eM11 * xform->eM22 == xform->eM12 * xform->eM21) return FALSE;
552
553     TRACE("eM11 %f eM12 %f eM21 %f eM22 %f eDx %f eDy %f\n",
554         xform->eM11, xform->eM12, xform->eM21, xform->eM22, xform->eDx, xform->eDy);
555
556     if ((dc = get_dc_ptr( hdc )))
557     {
558         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetWorldTransform );
559         if (dc->GraphicsMode == GM_ADVANCED)
560             ret = physdev->funcs->pSetWorldTransform( physdev, xform );
561         release_dc_ptr( dc );
562     }
563     return ret;
564 }
565
566
567 /***********************************************************************
568  *           SetVirtualResolution   (GDI32.@)
569  *
570  * Undocumented on msdn.
571  *
572  * Changes the values of screen size in pixels and millimeters used by
573  * the mapping mode functions.
574  *
575  * PARAMS
576  *     hdc       [I] Device context
577  *     horz_res  [I] Width in pixels  (equivalent to HORZRES device cap).
578  *     vert_res  [I] Height in pixels (equivalent to VERTRES device cap).
579  *     horz_size [I] Width in mm      (equivalent to HORZSIZE device cap).
580  *     vert_size [I] Height in mm     (equivalent to VERTSIZE device cap).
581  *
582  * RETURNS
583  *    TRUE if successful.
584  *    FALSE if any (but not all) of the last four params are zero.
585  *
586  * NOTES
587  *    This doesn't change the values returned by GetDeviceCaps, just the
588  *    scaling of the mapping modes.
589  *
590  *    Calling with the last four params equal to zero sets the values
591  *    back to their defaults obtained by calls to GetDeviceCaps.
592  */
593 BOOL WINAPI SetVirtualResolution(HDC hdc, DWORD horz_res, DWORD vert_res,
594                                  DWORD horz_size, DWORD vert_size)
595 {
596     DC * dc;
597     TRACE("(%p %d %d %d %d)\n", hdc, horz_res, vert_res, horz_size, vert_size);
598
599     if(horz_res == 0 && vert_res == 0 && horz_size == 0 && vert_size == 0)
600     {
601         horz_res  = GetDeviceCaps(hdc, HORZRES);
602         vert_res  = GetDeviceCaps(hdc, VERTRES);
603         horz_size = GetDeviceCaps(hdc, HORZSIZE);
604         vert_size = GetDeviceCaps(hdc, VERTSIZE);
605     }
606     else if(horz_res == 0 || vert_res == 0 || horz_size == 0 || vert_size == 0)
607         return FALSE;
608
609     dc = get_dc_ptr( hdc );
610     if (!dc) return FALSE;
611
612     dc->virtual_res.cx  = horz_res;
613     dc->virtual_res.cy  = vert_res;
614     dc->virtual_size.cx = horz_size;
615     dc->virtual_size.cy = vert_size;
616
617     release_dc_ptr( dc );
618     return TRUE;
619 }