windowscodecs: Add support for 32-bit TGA images.
[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 "wownt32.h"
27 #include "gdi_private.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(dc);
31
32
33 /***********************************************************************
34  *           MAPPING_FixIsotropic
35  *
36  * Fix viewport extensions for isotropic mode.
37  */
38 static void MAPPING_FixIsotropic( DC * dc )
39 {
40     double xdim = fabs((double)dc->vportExtX * dc->virtual_size.cx /
41                   (dc->virtual_res.cx * dc->wndExtX));
42     double ydim = fabs((double)dc->vportExtY * dc->virtual_size.cy /
43                   (dc->virtual_res.cy * dc->wndExtY));
44
45     if (xdim > ydim)
46     {
47         INT mincx = (dc->vportExtX >= 0) ? 1 : -1;
48         dc->vportExtX = floor(dc->vportExtX * ydim / xdim + 0.5);
49         if (!dc->vportExtX) dc->vportExtX = mincx;
50     }
51     else
52     {
53         INT mincy = (dc->vportExtY >= 0) ? 1 : -1;
54         dc->vportExtY = floor(dc->vportExtY * xdim / ydim + 0.5);
55         if (!dc->vportExtY) dc->vportExtY = mincy;
56     }
57 }
58
59
60 /***********************************************************************
61  *           DPtoLP    (GDI32.@)
62  */
63 BOOL WINAPI DPtoLP( HDC hdc, LPPOINT points, INT count )
64 {
65     DC * dc = get_dc_ptr( hdc );
66     if (!dc) return FALSE;
67
68     if (dc->vport2WorldValid)
69     {
70         while (count--)
71         {
72             double x = points->x;
73             double y = points->y;
74             points->x = floor( x * dc->xformVport2World.eM11 +
75                                y * dc->xformVport2World.eM21 +
76                                dc->xformVport2World.eDx + 0.5 );
77             points->y = floor( x * dc->xformVport2World.eM12 +
78                                y * dc->xformVport2World.eM22 +
79                                dc->xformVport2World.eDy + 0.5 );
80             points++;
81         }
82     }
83     release_dc_ptr( dc );
84     return (count < 0);
85 }
86
87
88 /***********************************************************************
89  *           LPtoDP    (GDI32.@)
90  */
91 BOOL WINAPI LPtoDP( HDC hdc, LPPOINT points, INT count )
92 {
93     DC * dc = get_dc_ptr( hdc );
94     if (!dc) return FALSE;
95
96     while (count--)
97     {
98         double x = points->x;
99         double y = points->y;
100         points->x = floor( x * dc->xformWorld2Vport.eM11 +
101                            y * dc->xformWorld2Vport.eM21 +
102                            dc->xformWorld2Vport.eDx + 0.5 );
103         points->y = floor( x * dc->xformWorld2Vport.eM12 +
104                            y * dc->xformWorld2Vport.eM22 +
105                            dc->xformWorld2Vport.eDy + 0.5 );
106         points++;
107     }
108     release_dc_ptr( dc );
109     return TRUE;
110 }
111
112
113 /***********************************************************************
114  *           SetMapMode    (GDI32.@)
115  */
116 INT WINAPI SetMapMode( HDC hdc, INT mode )
117 {
118     INT ret;
119     INT horzSize, vertSize, horzRes, vertRes;
120
121     DC * dc = get_dc_ptr( hdc );
122     if (!dc) return 0;
123     if (dc->funcs->pSetMapMode)
124     {
125         if((ret = dc->funcs->pSetMapMode( dc->physDev, mode )) != TRUE)
126         {
127             if(ret == GDI_NO_MORE_WORK)
128                 ret = TRUE;
129             goto done;
130         }
131     }
132
133     TRACE("%p %d\n", hdc, mode );
134
135     ret = dc->MapMode;
136
137     if (mode == dc->MapMode && (mode == MM_ISOTROPIC || mode == MM_ANISOTROPIC))
138         goto done;
139
140     horzSize = dc->virtual_size.cx;
141     vertSize = dc->virtual_size.cy;
142     horzRes  = dc->virtual_res.cx;
143     vertRes  = dc->virtual_res.cy;
144     switch(mode)
145     {
146     case MM_TEXT:
147         dc->wndExtX   = 1;
148         dc->wndExtY   = 1;
149         dc->vportExtX = 1;
150         dc->vportExtY = 1;
151         break;
152     case MM_LOMETRIC:
153     case MM_ISOTROPIC:
154         dc->wndExtX   = horzSize * 10;
155         dc->wndExtY   = vertSize * 10;
156         dc->vportExtX = horzRes;
157         dc->vportExtY = -vertRes;
158         break;
159     case MM_HIMETRIC:
160         dc->wndExtX   = horzSize * 100;
161         dc->wndExtY   = vertSize * 100;
162         dc->vportExtX = horzRes;
163         dc->vportExtY = -vertRes;
164         break;
165     case MM_LOENGLISH:
166         dc->wndExtX   = MulDiv(1000, horzSize, 254);
167         dc->wndExtY   = MulDiv(1000, vertSize, 254);
168         dc->vportExtX = horzRes;
169         dc->vportExtY = -vertRes;
170         break;
171     case MM_HIENGLISH:
172         dc->wndExtX   = MulDiv(10000, horzSize, 254);
173         dc->wndExtY   = MulDiv(10000, vertSize, 254);
174         dc->vportExtX = horzRes;
175         dc->vportExtY = -vertRes;
176         break;
177     case MM_TWIPS:
178         dc->wndExtX   = MulDiv(14400, horzSize, 254);
179         dc->wndExtY   = MulDiv(14400, vertSize, 254);
180         dc->vportExtX = horzRes;
181         dc->vportExtY = -vertRes;
182         break;
183     case MM_ANISOTROPIC:
184         break;
185     default:
186         goto done;
187     }
188     /* RTL layout is always MM_ANISOTROPIC */
189     if (!(dc->layout & LAYOUT_RTL)) dc->MapMode = mode;
190     DC_UpdateXforms( dc );
191  done:
192     release_dc_ptr( dc );
193     return ret;
194 }
195
196
197 /***********************************************************************
198  *           SetViewportExtEx    (GDI32.@)
199  */
200 BOOL WINAPI SetViewportExtEx( HDC hdc, INT x, INT y, LPSIZE size )
201 {
202     INT ret = TRUE;
203     DC * dc = get_dc_ptr( hdc );
204     if (!dc) return FALSE;
205     if (dc->funcs->pSetViewportExt)
206     {
207         if((ret = dc->funcs->pSetViewportExt( dc->physDev, x, y )) != TRUE)
208         {
209             if(ret == GDI_NO_MORE_WORK)
210                 ret = TRUE;
211             goto done;
212         }
213     }
214     if (size)
215     {
216         size->cx = dc->vportExtX;
217         size->cy = dc->vportExtY;
218     }
219     if ((dc->MapMode != MM_ISOTROPIC) && (dc->MapMode != MM_ANISOTROPIC))
220         goto done;
221     if (!x || !y)
222     {
223         ret = FALSE;
224         goto done;
225     }
226     dc->vportExtX = x;
227     dc->vportExtY = y;
228     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
229     DC_UpdateXforms( dc );
230  done:
231     release_dc_ptr( dc );
232     return ret;
233 }
234
235
236 /***********************************************************************
237  *           SetViewportOrgEx    (GDI32.@)
238  */
239 BOOL WINAPI SetViewportOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
240 {
241     INT ret = TRUE;
242     DC * dc = get_dc_ptr( hdc );
243     if (!dc) return FALSE;
244     if (dc->funcs->pSetViewportOrg)
245     {
246         if((ret = dc->funcs->pSetViewportOrg( dc->physDev, x, y )) != TRUE)
247         {
248             if(ret == GDI_NO_MORE_WORK)
249                 ret = TRUE;
250             goto done;
251         }
252     }
253     if (pt)
254     {
255         pt->x = dc->vportOrgX;
256         pt->y = dc->vportOrgY;
257     }
258     dc->vportOrgX = x;
259     dc->vportOrgY = y;
260     DC_UpdateXforms( dc );
261
262  done:
263     release_dc_ptr( dc );
264     return ret;
265 }
266
267
268 /***********************************************************************
269  *           SetWindowExtEx    (GDI32.@)
270  */
271 BOOL WINAPI SetWindowExtEx( HDC hdc, INT x, INT y, LPSIZE size )
272 {
273     INT ret = TRUE;
274     DC * dc = get_dc_ptr( hdc );
275     if (!dc) return FALSE;
276     if (dc->funcs->pSetWindowExt)
277     {
278         if((ret = dc->funcs->pSetWindowExt( dc->physDev, x, y )) != TRUE)
279         {
280             if(ret == GDI_NO_MORE_WORK)
281                 ret = TRUE;
282             goto done;
283         }
284     }
285     if (size)
286     {
287         size->cx = dc->wndExtX;
288         size->cy = dc->wndExtY;
289     }
290     if ((dc->MapMode != MM_ISOTROPIC) && (dc->MapMode != MM_ANISOTROPIC))
291         goto done;
292     if (!x || !y)
293     {
294         ret = FALSE;
295         goto done;
296     }
297     dc->wndExtX = x;
298     dc->wndExtY = y;
299     /* The API docs say that you should call SetWindowExtEx before
300        SetViewportExtEx. This advice does not imply that Windows
301        doesn't ensure the isotropic mapping after SetWindowExtEx! */
302     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
303     DC_UpdateXforms( dc );
304  done:
305     release_dc_ptr( dc );
306     return ret;
307 }
308
309
310 /***********************************************************************
311  *           SetWindowOrgEx    (GDI32.@)
312  */
313 BOOL WINAPI SetWindowOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
314 {
315     INT ret = TRUE;
316     DC * dc = get_dc_ptr( hdc );
317     if (!dc) return FALSE;
318     if (dc->funcs->pSetWindowOrg)
319     {
320         if((ret = dc->funcs->pSetWindowOrg( dc->physDev, x, y )) != TRUE)
321         {
322             if(ret == GDI_NO_MORE_WORK)
323                 ret = TRUE;
324             goto done;
325         }
326     }
327     if (pt)
328     {
329         pt->x = dc->wndOrgX;
330         pt->y = dc->wndOrgY;
331     }
332     dc->wndOrgX = x;
333     dc->wndOrgY = y;
334     DC_UpdateXforms( dc );
335  done:
336     release_dc_ptr( dc );
337     return ret;
338 }
339
340
341 /***********************************************************************
342  *           OffsetViewportOrgEx    (GDI32.@)
343  */
344 BOOL WINAPI OffsetViewportOrgEx( HDC hdc, INT x, INT y, LPPOINT pt)
345 {
346     INT ret = TRUE;
347     DC * dc = get_dc_ptr( hdc );
348     if (!dc) return FALSE;
349     if (dc->funcs->pOffsetViewportOrg)
350     {
351         if((ret = dc->funcs->pOffsetViewportOrg( dc->physDev, x, y )) != TRUE)
352         {
353             if(ret == GDI_NO_MORE_WORK)
354                 ret = TRUE;
355             goto done;
356         }
357     }
358     if (pt)
359     {
360         pt->x = dc->vportOrgX;
361         pt->y = dc->vportOrgY;
362     }
363     dc->vportOrgX += x;
364     dc->vportOrgY += y;
365     DC_UpdateXforms( dc );
366  done:
367     release_dc_ptr( dc );
368     return ret;
369 }
370
371
372 /***********************************************************************
373  *           OffsetWindowOrgEx    (GDI32.@)
374  */
375 BOOL WINAPI OffsetWindowOrgEx( HDC hdc, INT x, INT y, LPPOINT pt )
376 {
377     INT ret = TRUE;
378     DC * dc = get_dc_ptr( hdc );
379     if (!dc) return FALSE;
380     if (dc->funcs->pOffsetWindowOrg)
381     {
382         if((ret = dc->funcs->pOffsetWindowOrg( dc->physDev, x, y )) != TRUE)
383         {
384             if(ret == GDI_NO_MORE_WORK)
385                 ret = TRUE;
386             goto done;
387         }
388     }
389     if (pt)
390     {
391         pt->x = dc->wndOrgX;
392         pt->y = dc->wndOrgY;
393     }
394     dc->wndOrgX += x;
395     dc->wndOrgY += y;
396     DC_UpdateXforms( dc );
397  done:
398     release_dc_ptr( dc );
399     return ret;
400 }
401
402
403 /***********************************************************************
404  *           ScaleViewportExtEx    (GDI32.@)
405  */
406 BOOL WINAPI ScaleViewportExtEx( HDC hdc, INT xNum, INT xDenom,
407                                     INT yNum, INT yDenom, LPSIZE size )
408 {
409     INT ret = TRUE;
410     DC * dc = get_dc_ptr( hdc );
411     if (!dc) return FALSE;
412     if (dc->funcs->pScaleViewportExt)
413     {
414         if((ret = dc->funcs->pScaleViewportExt( dc->physDev, xNum, xDenom, yNum, yDenom )) != TRUE)
415         {
416             if(ret == GDI_NO_MORE_WORK)
417                 ret = TRUE;
418             goto done;
419         }
420     }
421     if (size)
422     {
423         size->cx = dc->vportExtX;
424         size->cy = dc->vportExtY;
425     }
426     if ((dc->MapMode != MM_ISOTROPIC) && (dc->MapMode != MM_ANISOTROPIC))
427         goto done;
428     if (!xNum || !xDenom || !yNum || !yDenom)
429     {
430         ret = FALSE;
431         goto done;
432     }
433     dc->vportExtX = (dc->vportExtX * xNum) / xDenom;
434     dc->vportExtY = (dc->vportExtY * yNum) / yDenom;
435     if (dc->vportExtX == 0) dc->vportExtX = 1;
436     if (dc->vportExtY == 0) dc->vportExtY = 1;
437     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
438     DC_UpdateXforms( dc );
439  done:
440     release_dc_ptr( dc );
441     return ret;
442 }
443
444
445 /***********************************************************************
446  *           ScaleWindowExtEx    (GDI32.@)
447  */
448 BOOL WINAPI ScaleWindowExtEx( HDC hdc, INT xNum, INT xDenom,
449                                   INT yNum, INT yDenom, LPSIZE size )
450 {
451     INT ret = TRUE;
452     DC * dc = get_dc_ptr( hdc );
453     if (!dc) return FALSE;
454     if (dc->funcs->pScaleWindowExt)
455     {
456         if((ret = dc->funcs->pScaleWindowExt( dc->physDev, xNum, xDenom, yNum, yDenom )) != TRUE)
457         {
458             if(ret == GDI_NO_MORE_WORK)
459                 ret = TRUE;
460             goto done;
461         }
462     }
463     if (size)
464     {
465         size->cx = dc->wndExtX;
466         size->cy = dc->wndExtY;
467     }
468     if ((dc->MapMode != MM_ISOTROPIC) && (dc->MapMode != MM_ANISOTROPIC))
469         goto done;
470     if (!xNum || !xDenom || !xNum || !yDenom)
471     {
472         ret = FALSE;
473         goto done;
474     }
475     dc->wndExtX = (dc->wndExtX * xNum) / xDenom;
476     dc->wndExtY = (dc->wndExtY * yNum) / yDenom;
477     if (dc->wndExtX == 0) dc->wndExtX = 1;
478     if (dc->wndExtY == 0) dc->wndExtY = 1;
479     if (dc->MapMode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
480     DC_UpdateXforms( dc );
481  done:
482     release_dc_ptr( dc );
483     return ret;
484 }
485
486 /***********************************************************************
487  *           SetVirtualResolution   (GDI32.@)
488  *
489  * Undocumented on msdn.
490  *
491  * Changes the values of screen size in pixels and millimeters used by
492  * the mapping mode functions.
493  *
494  * PARAMS
495  *     hdc       [I] Device context
496  *     horz_res  [I] Width in pixels  (equivalent to HORZRES device cap).
497  *     vert_res  [I] Height in pixels (equivalent to VERTRES device cap).
498  *     horz_size [I] Width in mm      (equivalent to HORZSIZE device cap).
499  *     vert_size [I] Height in mm     (equivalent to VERTSIZE device cap).
500  *
501  * RETURNS
502  *    TRUE if successful.
503  *    FALSE if any (but not all) of the last four params are zero.
504  *
505  * NOTES
506  *    This doesn't change the values returned by GetDeviceCaps, just the
507  *    scaling of the mapping modes.
508  *
509  *    Calling with the last four params equal to zero sets the values
510  *    back to their defaults obtained by calls to GetDeviceCaps.
511  */
512 BOOL WINAPI SetVirtualResolution(HDC hdc, DWORD horz_res, DWORD vert_res,
513                                  DWORD horz_size, DWORD vert_size)
514 {
515     DC * dc;
516     TRACE("(%p %d %d %d %d)\n", hdc, horz_res, vert_res, horz_size, vert_size);
517
518     if(horz_res == 0 && vert_res == 0 && horz_size == 0 && vert_size == 0)
519     {
520         horz_res  = GetDeviceCaps(hdc, HORZRES);
521         vert_res  = GetDeviceCaps(hdc, VERTRES);
522         horz_size = GetDeviceCaps(hdc, HORZSIZE);
523         vert_size = GetDeviceCaps(hdc, VERTSIZE);
524     }
525     else if(horz_res == 0 || vert_res == 0 || horz_size == 0 || vert_size == 0)
526         return FALSE;
527
528     dc = get_dc_ptr( hdc );
529     if (!dc) return FALSE;
530
531     dc->virtual_res.cx  = horz_res;
532     dc->virtual_res.cy  = vert_res;
533     dc->virtual_size.cx = horz_size;
534     dc->virtual_size.cy = vert_size;
535
536     release_dc_ptr( dc );
537     return TRUE;
538 }