gdi32: Keep track of changes to the brush rop, so that we can perform lazy realisatio...
[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 CDECL 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 CDECL 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 CDECL nulldrv_ScaleViewportExtEx( PHYSDEV dev, INT x_num, INT x_denom, INT y_num, INT y_denom,
94                                        SIZE *size )
95 {
96     DC *dc = get_nulldrv_dc( dev );
97
98     if (size)
99     {
100         size->cx = dc->vportExtX;
101         size->cy = dc->vportExtY;
102     }
103     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
104     if (!x_num || !x_denom || !y_num || !y_denom) return FALSE;
105
106     dc->vportExtX = (dc->vportExtX * x_num) / x_denom;
107     dc->vportExtY = (dc->vportExtY * y_num) / y_denom;
108     if (dc->vportExtX == 0) dc->vportExtX = 1;
109     if (dc->vportExtY == 0) dc->vportExtY = 1;
110     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
111     DC_UpdateXforms( dc );
112     return TRUE;
113 }
114
115 BOOL CDECL nulldrv_ScaleWindowExtEx( PHYSDEV dev, INT x_num, INT x_denom, INT y_num, INT y_denom,
116                                      SIZE *size )
117 {
118     DC *dc = get_nulldrv_dc( dev );
119
120     if (size)
121     {
122         size->cx = dc->wndExtX;
123         size->cy = dc->wndExtY;
124     }
125     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
126     if (!x_num || !x_denom || !y_num || !y_denom) return FALSE;
127
128     dc->wndExtX = (dc->wndExtX * x_num) / x_denom;
129     dc->wndExtY = (dc->wndExtY * y_num) / y_denom;
130     if (dc->wndExtX == 0) dc->wndExtX = 1;
131     if (dc->wndExtY == 0) dc->wndExtY = 1;
132     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
133     DC_UpdateXforms( dc );
134     return TRUE;
135 }
136
137 INT CDECL nulldrv_SetMapMode( PHYSDEV dev, INT mode )
138 {
139     DC *dc = get_nulldrv_dc( dev );
140     INT ret = dc->MapMode;
141     INT horzSize, vertSize, horzRes, vertRes;
142
143     if (mode == dc->MapMode && (mode == MM_ISOTROPIC || mode == MM_ANISOTROPIC)) return ret;
144
145     horzSize = dc->virtual_size.cx;
146     vertSize = dc->virtual_size.cy;
147     horzRes  = dc->virtual_res.cx;
148     vertRes  = dc->virtual_res.cy;
149     switch (mode)
150     {
151     case MM_TEXT:
152         dc->wndExtX   = 1;
153         dc->wndExtY   = 1;
154         dc->vportExtX = 1;
155         dc->vportExtY = 1;
156         break;
157     case MM_LOMETRIC:
158     case MM_ISOTROPIC:
159         dc->wndExtX   = horzSize * 10;
160         dc->wndExtY   = vertSize * 10;
161         dc->vportExtX = horzRes;
162         dc->vportExtY = -vertRes;
163         break;
164     case MM_HIMETRIC:
165         dc->wndExtX   = horzSize * 100;
166         dc->wndExtY   = vertSize * 100;
167         dc->vportExtX = horzRes;
168         dc->vportExtY = -vertRes;
169         break;
170     case MM_LOENGLISH:
171         dc->wndExtX   = MulDiv(1000, horzSize, 254);
172         dc->wndExtY   = MulDiv(1000, vertSize, 254);
173         dc->vportExtX = horzRes;
174         dc->vportExtY = -vertRes;
175         break;
176     case MM_HIENGLISH:
177         dc->wndExtX   = MulDiv(10000, horzSize, 254);
178         dc->wndExtY   = MulDiv(10000, vertSize, 254);
179         dc->vportExtX = horzRes;
180         dc->vportExtY = -vertRes;
181         break;
182     case MM_TWIPS:
183         dc->wndExtX   = MulDiv(14400, horzSize, 254);
184         dc->wndExtY   = MulDiv(14400, vertSize, 254);
185         dc->vportExtX = horzRes;
186         dc->vportExtY = -vertRes;
187         break;
188     case MM_ANISOTROPIC:
189         break;
190     default:
191         return 0;
192     }
193     /* RTL layout is always MM_ANISOTROPIC */
194     if (!(dc->layout & LAYOUT_RTL)) dc->MapMode = mode;
195     DC_UpdateXforms( dc );
196     return ret;
197 }
198
199 BOOL CDECL nulldrv_SetViewportExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
200 {
201     DC *dc = get_nulldrv_dc( dev );
202
203     if (size)
204     {
205         size->cx = dc->vportExtX;
206         size->cy = dc->vportExtY;
207     }
208     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
209     if (!cx || !cy) return FALSE;
210     dc->vportExtX = cx;
211     dc->vportExtY = cy;
212     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
213     DC_UpdateXforms( dc );
214     return TRUE;
215 }
216
217 BOOL CDECL nulldrv_SetViewportOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
218 {
219     DC *dc = get_nulldrv_dc( dev );
220
221     if (pt)
222     {
223         pt->x = dc->vportOrgX;
224         pt->y = dc->vportOrgY;
225     }
226     dc->vportOrgX = x;
227     dc->vportOrgY = y;
228     DC_UpdateXforms( dc );
229     return TRUE;
230 }
231
232 BOOL CDECL nulldrv_SetWindowExtEx( PHYSDEV dev, INT cx, INT cy, SIZE *size )
233 {
234     DC *dc = get_nulldrv_dc( dev );
235
236     if (size)
237     {
238         size->cx = dc->wndExtX;
239         size->cy = dc->wndExtY;
240     }
241     if (dc->MapMode != MM_ISOTROPIC && dc->MapMode != MM_ANISOTROPIC) return TRUE;
242     if (!cx || !cy) return FALSE;
243     dc->wndExtX = cx;
244     dc->wndExtY = cy;
245     /* The API docs say that you should call SetWindowExtEx before
246        SetViewportExtEx. This advice does not imply that Windows
247        doesn't ensure the isotropic mapping after SetWindowExtEx! */
248     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
249     DC_UpdateXforms( dc );
250     return TRUE;
251 }
252
253 BOOL CDECL nulldrv_SetWindowOrgEx( PHYSDEV dev, INT x, INT y, POINT *pt )
254 {
255     DC *dc = get_nulldrv_dc( dev );
256
257     if (pt)
258     {
259         pt->x = dc->wndOrgX;
260         pt->y = dc->wndOrgY;
261     }
262     dc->wndOrgX = x;
263     dc->wndOrgY = y;
264     DC_UpdateXforms( dc );
265     return TRUE;
266 }
267
268 BOOL CDECL nulldrv_ModifyWorldTransform( PHYSDEV dev, const XFORM *xform, DWORD mode )
269 {
270     DC *dc = get_nulldrv_dc( dev );
271
272     switch (mode)
273     {
274     case MWT_IDENTITY:
275         dc->xformWorld2Wnd.eM11 = 1.0f;
276         dc->xformWorld2Wnd.eM12 = 0.0f;
277         dc->xformWorld2Wnd.eM21 = 0.0f;
278         dc->xformWorld2Wnd.eM22 = 1.0f;
279         dc->xformWorld2Wnd.eDx  = 0.0f;
280         dc->xformWorld2Wnd.eDy  = 0.0f;
281         break;
282     case MWT_LEFTMULTIPLY:
283         CombineTransform( &dc->xformWorld2Wnd, xform, &dc->xformWorld2Wnd );
284         break;
285     case MWT_RIGHTMULTIPLY:
286         CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd, xform );
287         break;
288     default:
289         return FALSE;
290     }
291     DC_UpdateXforms( dc );
292     return TRUE;
293 }
294
295 BOOL CDECL nulldrv_SetWorldTransform( PHYSDEV dev, const XFORM *xform )
296 {
297     DC *dc = get_nulldrv_dc( dev );
298
299     dc->xformWorld2Wnd = *xform;
300     DC_UpdateXforms( dc );
301     return TRUE;
302 }
303
304 /***********************************************************************
305  *           DPtoLP    (GDI32.@)
306  */
307 BOOL WINAPI DPtoLP( HDC hdc, LPPOINT points, INT count )
308 {
309     DC * dc = get_dc_ptr( hdc );
310     if (!dc) return FALSE;
311
312     if (dc->vport2WorldValid)
313     {
314         while (count--)
315         {
316             double x = points->x;
317             double y = points->y;
318             points->x = floor( x * dc->xformVport2World.eM11 +
319                                y * dc->xformVport2World.eM21 +
320                                dc->xformVport2World.eDx + 0.5 );
321             points->y = floor( x * dc->xformVport2World.eM12 +
322                                y * dc->xformVport2World.eM22 +
323                                dc->xformVport2World.eDy + 0.5 );
324             points++;
325         }
326     }
327     release_dc_ptr( dc );
328     return (count < 0);
329 }
330
331
332 /***********************************************************************
333  *           LPtoDP    (GDI32.@)
334  */
335 BOOL WINAPI LPtoDP( HDC hdc, LPPOINT points, INT count )
336 {
337     DC * dc = get_dc_ptr( hdc );
338     if (!dc) return FALSE;
339
340     while (count--)
341     {
342         double x = points->x;
343         double y = points->y;
344         points->x = floor( x * dc->xformWorld2Vport.eM11 +
345                            y * dc->xformWorld2Vport.eM21 +
346                            dc->xformWorld2Vport.eDx + 0.5 );
347         points->y = floor( x * dc->xformWorld2Vport.eM12 +
348                            y * dc->xformWorld2Vport.eM22 +
349                            dc->xformWorld2Vport.eDy + 0.5 );
350         points++;
351     }
352     release_dc_ptr( dc );
353     return TRUE;
354 }
355
356
357 /***********************************************************************
358  *           SetMapMode    (GDI32.@)
359  */
360 INT WINAPI SetMapMode( HDC hdc, INT mode )
361 {
362     INT ret = 0;
363     DC * dc = get_dc_ptr( hdc );
364
365     TRACE("%p %d\n", hdc, mode );
366
367     if (dc)
368     {
369         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetMapMode );
370         ret = physdev->funcs->pSetMapMode( physdev, mode );
371         release_dc_ptr( dc );
372     }
373     return ret;
374 }
375
376
377 /***********************************************************************
378  *           SetViewportExtEx    (GDI32.@)
379  */
380 BOOL WINAPI SetViewportExtEx( HDC hdc, INT x, INT y, LPSIZE size )
381 {
382     INT ret = FALSE;
383     DC * dc = get_dc_ptr( hdc );
384
385     if (dc)
386     {
387         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetViewportExtEx );
388         ret = physdev->funcs->pSetViewportExtEx( physdev, x, y, size );
389         release_dc_ptr( dc );
390     }
391     return ret;
392 }
393
394
395 /***********************************************************************
396  *           SetViewportOrgEx    (GDI32.@)
397  */
398 BOOL WINAPI SetViewportOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
399 {
400     INT ret = FALSE;
401     DC * dc = get_dc_ptr( hdc );
402
403     if (dc)
404     {
405         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetViewportOrgEx );
406         ret = physdev->funcs->pSetViewportOrgEx( physdev, x, y, pt );
407         release_dc_ptr( dc );
408     }
409     return ret;
410 }
411
412
413 /***********************************************************************
414  *           SetWindowExtEx    (GDI32.@)
415  */
416 BOOL WINAPI SetWindowExtEx( HDC hdc, INT x, INT y, LPSIZE size )
417 {
418     INT ret = FALSE;
419     DC * dc = get_dc_ptr( hdc );
420
421     if (dc)
422     {
423         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetWindowExtEx );
424         ret = physdev->funcs->pSetWindowExtEx( physdev, x, y, size );
425         release_dc_ptr( dc );
426     }
427     return ret;
428 }
429
430
431 /***********************************************************************
432  *           SetWindowOrgEx    (GDI32.@)
433  */
434 BOOL WINAPI SetWindowOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
435 {
436     INT ret = FALSE;
437     DC * dc = get_dc_ptr( hdc );
438
439     if (dc)
440     {
441         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetWindowOrgEx );
442         ret = physdev->funcs->pSetWindowOrgEx( physdev, x, y, pt );
443         release_dc_ptr( dc );
444     }
445     return ret;
446 }
447
448
449 /***********************************************************************
450  *           OffsetViewportOrgEx    (GDI32.@)
451  */
452 BOOL WINAPI OffsetViewportOrgEx( HDC hdc, INT x, INT y, LPPOINT pt)
453 {
454     INT ret = FALSE;
455     DC * dc = get_dc_ptr( hdc );
456
457     if (dc)
458     {
459         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pOffsetViewportOrgEx );
460         ret = physdev->funcs->pOffsetViewportOrgEx( physdev, x, y, pt );
461         release_dc_ptr( dc );
462     }
463     return ret;
464 }
465
466
467 /***********************************************************************
468  *           OffsetWindowOrgEx    (GDI32.@)
469  */
470 BOOL WINAPI OffsetWindowOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
471 {
472     INT ret = FALSE;
473     DC * dc = get_dc_ptr( hdc );
474
475     if (dc)
476     {
477         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pOffsetWindowOrgEx );
478         ret = physdev->funcs->pOffsetWindowOrgEx( physdev, x, y, pt );
479         release_dc_ptr( dc );
480     }
481     return ret;
482 }
483
484
485 /***********************************************************************
486  *           ScaleViewportExtEx    (GDI32.@)
487  */
488 BOOL WINAPI ScaleViewportExtEx( HDC hdc, INT xNum, INT xDenom,
489                                     INT yNum, INT yDenom, LPSIZE size )
490 {
491     INT ret = FALSE;
492     DC * dc = get_dc_ptr( hdc );
493
494     if (dc)
495     {
496         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pScaleViewportExtEx );
497         ret = physdev->funcs->pScaleViewportExtEx( physdev, xNum, xDenom, yNum, yDenom, size );
498         release_dc_ptr( dc );
499     }
500     return ret;
501 }
502
503
504 /***********************************************************************
505  *           ScaleWindowExtEx    (GDI32.@)
506  */
507 BOOL WINAPI ScaleWindowExtEx( HDC hdc, INT xNum, INT xDenom,
508                                   INT yNum, INT yDenom, LPSIZE size )
509 {
510     INT ret = FALSE;
511     DC * dc = get_dc_ptr( hdc );
512
513     if (dc)
514     {
515         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pScaleWindowExtEx );
516         ret = physdev->funcs->pScaleWindowExtEx( physdev, xNum, xDenom, yNum, yDenom, size );
517         release_dc_ptr( dc );
518     }
519     return ret;
520 }
521
522
523 /****************************************************************************
524  *           ModifyWorldTransform   (GDI32.@)
525  */
526 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform, DWORD mode )
527 {
528     BOOL ret = FALSE;
529     DC *dc;
530
531     if (!xform && mode != MWT_IDENTITY) return FALSE;
532     if ((dc = get_dc_ptr( hdc )))
533     {
534         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pModifyWorldTransform );
535         if (dc->GraphicsMode == GM_ADVANCED)
536             ret = physdev->funcs->pModifyWorldTransform( physdev, xform, mode );
537         release_dc_ptr( dc );
538     }
539     return ret;
540 }
541
542
543 /***********************************************************************
544  *           SetWorldTransform    (GDI32.@)
545  */
546 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
547 {
548     BOOL ret = FALSE;
549     DC *dc;
550
551     if (!xform) return FALSE;
552     /* The transform must conform to (eM11 * eM22 != eM12 * eM21) requirement */
553     if (xform->eM11 * xform->eM22 == xform->eM12 * xform->eM21) return FALSE;
554
555     TRACE("eM11 %f eM12 %f eM21 %f eM22 %f eDx %f eDy %f\n",
556         xform->eM11, xform->eM12, xform->eM21, xform->eM22, xform->eDx, xform->eDy);
557
558     if ((dc = get_dc_ptr( hdc )))
559     {
560         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetWorldTransform );
561         if (dc->GraphicsMode == GM_ADVANCED)
562             ret = physdev->funcs->pSetWorldTransform( physdev, xform );
563         release_dc_ptr( dc );
564     }
565     return ret;
566 }
567
568
569 /***********************************************************************
570  *           SetVirtualResolution   (GDI32.@)
571  *
572  * Undocumented on msdn.
573  *
574  * Changes the values of screen size in pixels and millimeters used by
575  * the mapping mode functions.
576  *
577  * PARAMS
578  *     hdc       [I] Device context
579  *     horz_res  [I] Width in pixels  (equivalent to HORZRES device cap).
580  *     vert_res  [I] Height in pixels (equivalent to VERTRES device cap).
581  *     horz_size [I] Width in mm      (equivalent to HORZSIZE device cap).
582  *     vert_size [I] Height in mm     (equivalent to VERTSIZE device cap).
583  *
584  * RETURNS
585  *    TRUE if successful.
586  *    FALSE if any (but not all) of the last four params are zero.
587  *
588  * NOTES
589  *    This doesn't change the values returned by GetDeviceCaps, just the
590  *    scaling of the mapping modes.
591  *
592  *    Calling with the last four params equal to zero sets the values
593  *    back to their defaults obtained by calls to GetDeviceCaps.
594  */
595 BOOL WINAPI SetVirtualResolution(HDC hdc, DWORD horz_res, DWORD vert_res,
596                                  DWORD horz_size, DWORD vert_size)
597 {
598     DC * dc;
599     TRACE("(%p %d %d %d %d)\n", hdc, horz_res, vert_res, horz_size, vert_size);
600
601     if(horz_res == 0 && vert_res == 0 && horz_size == 0 && vert_size == 0)
602     {
603         horz_res  = GetDeviceCaps(hdc, HORZRES);
604         vert_res  = GetDeviceCaps(hdc, VERTRES);
605         horz_size = GetDeviceCaps(hdc, HORZSIZE);
606         vert_size = GetDeviceCaps(hdc, VERTSIZE);
607     }
608     else if(horz_res == 0 || vert_res == 0 || horz_size == 0 || vert_size == 0)
609         return FALSE;
610
611     dc = get_dc_ptr( hdc );
612     if (!dc) return FALSE;
613
614     dc->virtual_res.cx  = horz_res;
615     dc->virtual_res.cy  = vert_res;
616     dc->virtual_size.cx = horz_size;
617     dc->virtual_size.cy = vert_size;
618
619     release_dc_ptr( dc );
620     return TRUE;
621 }