winepulse: Use GetModuleFileName() instead of hardcoded module filename for registry...
[wine.git] / dlls / win32u / mapping.c
blob65f276e853f649155f8a1955014780196afd6832
1 /*
2 * GDI mapping mode functions
4 * Copyright 1993 Alexandre Julliard
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.
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.
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
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include <stdarg.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "ntgdi_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(dc);
36 /* copied from kernelbase */
37 int muldiv( int a, int b, int c )
39 LONGLONG ret;
41 if (!c) return -1;
43 /* We want to deal with a positive divisor to simplify the logic. */
44 if (c < 0)
46 a = -a;
47 c = -c;
50 /* If the result is positive, we "add" to round. else, we subtract to round. */
51 if ((a < 0 && b < 0) || (a >= 0 && b >= 0))
52 ret = (((LONGLONG)a * b) + (c / 2)) / c;
53 else
54 ret = (((LONGLONG)a * b) - (c / 2)) / c;
56 if (ret > 2147483647 || ret < -2147483647) return -1;
57 return ret;
60 static SIZE get_dc_virtual_size( DC *dc )
62 SIZE ret = dc->attr->virtual_size;
64 if (!ret.cx)
66 ret.cx = NtGdiGetDeviceCaps( dc->hSelf, HORZSIZE );
67 ret.cy = NtGdiGetDeviceCaps( dc->hSelf, VERTSIZE );
69 return ret;
72 static SIZE get_dc_virtual_res( DC *dc )
74 SIZE ret = dc->attr->virtual_res;
76 if (!ret.cx)
78 ret.cx = NtGdiGetDeviceCaps( dc->hSelf, HORZRES );
79 ret.cy = NtGdiGetDeviceCaps( dc->hSelf, VERTRES );
81 return ret;
84 /***********************************************************************
85 * MAPPING_FixIsotropic
87 * Fix viewport extensions for isotropic mode.
89 static void MAPPING_FixIsotropic( DC * dc )
91 SIZE virtual_size = get_dc_virtual_size( dc );
92 SIZE virtual_res = get_dc_virtual_res( dc );
93 double xdim = fabs((double)dc->attr->vport_ext.cx * virtual_size.cx /
94 (virtual_res.cx * dc->attr->wnd_ext.cx));
95 double ydim = fabs((double)dc->attr->vport_ext.cy * virtual_size.cy /
96 (virtual_res.cy * dc->attr->wnd_ext.cy));
98 if (xdim > ydim)
100 INT mincx = (dc->attr->vport_ext.cx >= 0) ? 1 : -1;
101 dc->attr->vport_ext.cx = GDI_ROUND( dc->attr->vport_ext.cx * ydim / xdim );
102 if (!dc->attr->vport_ext.cx) dc->attr->vport_ext.cx = mincx;
104 else
106 INT mincy = (dc->attr->vport_ext.cy >= 0) ? 1 : -1;
107 dc->attr->vport_ext.cy = GDI_ROUND( dc->attr->vport_ext.cy * xdim / ydim );
108 if (!dc->attr->vport_ext.cy) dc->attr->vport_ext.cy = mincy;
113 BOOL set_map_mode( DC *dc, int mode )
115 SIZE virtual_size, virtual_res;
117 if (mode == dc->attr->map_mode && (mode == MM_ISOTROPIC || mode == MM_ANISOTROPIC))
118 return TRUE;
120 switch (mode)
122 case MM_TEXT:
123 dc->attr->wnd_ext.cx = 1;
124 dc->attr->wnd_ext.cy = 1;
125 dc->attr->vport_ext.cx = 1;
126 dc->attr->vport_ext.cy = 1;
127 break;
128 case MM_LOMETRIC:
129 case MM_ISOTROPIC:
130 virtual_size = get_dc_virtual_size( dc );
131 virtual_res = get_dc_virtual_res( dc );
132 dc->attr->wnd_ext.cx = virtual_size.cx * 10;
133 dc->attr->wnd_ext.cy = virtual_size.cy * 10;
134 dc->attr->vport_ext.cx = virtual_res.cx;
135 dc->attr->vport_ext.cy = -virtual_res.cy;
136 break;
137 case MM_HIMETRIC:
138 virtual_size = get_dc_virtual_size( dc );
139 virtual_res = get_dc_virtual_res( dc );
140 dc->attr->wnd_ext.cx = virtual_size.cx * 100;
141 dc->attr->wnd_ext.cy = virtual_size.cy * 100;
142 dc->attr->vport_ext.cx = virtual_res.cx;
143 dc->attr->vport_ext.cy = -virtual_res.cy;
144 break;
145 case MM_LOENGLISH:
146 virtual_size = get_dc_virtual_size( dc );
147 virtual_res = get_dc_virtual_res( dc );
148 dc->attr->wnd_ext.cx = muldiv(1000, virtual_size.cx, 254);
149 dc->attr->wnd_ext.cy = muldiv(1000, virtual_size.cy, 254);
150 dc->attr->vport_ext.cx = virtual_res.cx;
151 dc->attr->vport_ext.cy = -virtual_res.cy;
152 break;
153 case MM_HIENGLISH:
154 virtual_size = get_dc_virtual_size( dc );
155 virtual_res = get_dc_virtual_res( dc );
156 dc->attr->wnd_ext.cx = muldiv(10000, virtual_size.cx, 254);
157 dc->attr->wnd_ext.cy = muldiv(10000, virtual_size.cy, 254);
158 dc->attr->vport_ext.cx = virtual_res.cx;
159 dc->attr->vport_ext.cy = -virtual_res.cy;
160 break;
161 case MM_TWIPS:
162 virtual_size = get_dc_virtual_size( dc );
163 virtual_res = get_dc_virtual_res( dc );
164 dc->attr->wnd_ext.cx = muldiv(14400, virtual_size.cx, 254);
165 dc->attr->wnd_ext.cy = muldiv(14400, virtual_size.cy, 254);
166 dc->attr->vport_ext.cx = virtual_res.cx;
167 dc->attr->vport_ext.cy = -virtual_res.cy;
168 break;
169 case MM_ANISOTROPIC:
170 break;
171 default:
172 return FALSE;
174 /* RTL layout is always MM_ANISOTROPIC */
175 if (!(dc->attr->layout & LAYOUT_RTL)) dc->attr->map_mode = mode;
176 DC_UpdateXforms( dc );
177 return TRUE;
180 /***********************************************************************
181 * dp_to_lp
183 * Internal version of DPtoLP that takes a DC *.
185 BOOL dp_to_lp( DC *dc, POINT *points, INT count )
187 if (dc->vport2WorldValid)
189 while (count--)
191 double x = points->x;
192 double y = points->y;
193 points->x = GDI_ROUND( x * dc->xformVport2World.eM11 +
194 y * dc->xformVport2World.eM21 +
195 dc->xformVport2World.eDx );
196 points->y = GDI_ROUND( x * dc->xformVport2World.eM12 +
197 y * dc->xformVport2World.eM22 +
198 dc->xformVport2World.eDy );
199 points++;
202 return (count < 0);
205 /***********************************************************************
206 * NtGdiTransformPoints (win32u.@)
208 BOOL WINAPI NtGdiTransformPoints( HDC hdc, const POINT *points_in, POINT *points_out,
209 INT count, UINT mode )
211 DC *dc = get_dc_ptr( hdc );
212 int i = 0;
213 BOOL ret = FALSE;
215 if (!dc) return FALSE;
217 switch (mode)
219 case NtGdiLPtoDP:
220 for (i = 0; i < count; i++)
222 double x = points_in[i].x;
223 double y = points_in[i].y;
224 points_out[i].x = GDI_ROUND( x * dc->xformWorld2Vport.eM11 +
225 y * dc->xformWorld2Vport.eM21 +
226 dc->xformWorld2Vport.eDx );
227 points_out[i].y = GDI_ROUND( x * dc->xformWorld2Vport.eM12 +
228 y * dc->xformWorld2Vport.eM22 +
229 dc->xformWorld2Vport.eDy );
231 ret = TRUE;
232 break;
234 case NtGdiDPtoLP:
235 if (!dc->vport2WorldValid) break;
236 for (i = 0; i < count; i++)
238 double x = points_in[i].x;
239 double y = points_in[i].y;
240 points_out[i].x = GDI_ROUND( x * dc->xformVport2World.eM11 +
241 y * dc->xformVport2World.eM21 +
242 dc->xformVport2World.eDx );
243 points_out[i].y = GDI_ROUND( x * dc->xformVport2World.eM12 +
244 y * dc->xformVport2World.eM22 +
245 dc->xformVport2World.eDy );
247 ret = TRUE;
248 break;
250 default:
251 WARN( "invalid mode %x\n", mode );
252 break;
255 release_dc_ptr( dc );
256 return ret;
260 /***********************************************************************
261 * lp_to_dp
263 * Internal version of LPtoDP that takes a DC *.
265 void lp_to_dp( DC *dc, POINT *points, INT count )
267 while (count--)
269 double x = points->x;
270 double y = points->y;
271 points->x = GDI_ROUND( x * dc->xformWorld2Vport.eM11 +
272 y * dc->xformWorld2Vport.eM21 +
273 dc->xformWorld2Vport.eDx );
274 points->y = GDI_ROUND( x * dc->xformWorld2Vport.eM12 +
275 y * dc->xformWorld2Vport.eM22 +
276 dc->xformWorld2Vport.eDy );
277 points++;
282 /***********************************************************************
283 * NtGdiComputeXformCoefficients (win32u.@)
285 BOOL WINAPI NtGdiComputeXformCoefficients( HDC hdc )
287 DC *dc;
289 if (!(dc = get_dc_ptr( hdc ))) return FALSE;
290 if (dc->attr->map_mode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
291 DC_UpdateXforms( dc );
292 release_dc_ptr( dc );
293 return TRUE;
297 /***********************************************************************
298 * NtGdiScaleViewportExtEx (win32u.@)
300 BOOL WINAPI NtGdiScaleViewportExtEx( HDC hdc, INT x_num, INT x_denom,
301 INT y_num, INT y_denom, SIZE *size )
303 DC *dc;
305 if ((!(dc = get_dc_ptr( hdc )))) return FALSE;
307 if (size) *size = dc->attr->vport_ext;
309 if (dc->attr->map_mode == MM_ISOTROPIC || dc->attr->map_mode == MM_ANISOTROPIC)
311 if (!x_num || !x_denom || !y_num || !y_denom)
313 release_dc_ptr( dc );
314 return FALSE;
317 dc->attr->vport_ext.cx = (dc->attr->vport_ext.cx * x_num) / x_denom;
318 dc->attr->vport_ext.cy = (dc->attr->vport_ext.cy * y_num) / y_denom;
319 if (dc->attr->vport_ext.cx == 0) dc->attr->vport_ext.cx = 1;
320 if (dc->attr->vport_ext.cy == 0) dc->attr->vport_ext.cy = 1;
321 if (dc->attr->map_mode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
322 DC_UpdateXforms( dc );
325 release_dc_ptr( dc );
326 return TRUE;
330 /***********************************************************************
331 * NtGdiScaleWindowExtEx (win32u.@)
333 BOOL WINAPI NtGdiScaleWindowExtEx( HDC hdc, INT x_num, INT x_denom,
334 INT y_num, INT y_denom, SIZE *size )
336 DC *dc;
338 if ((!(dc = get_dc_ptr( hdc )))) return FALSE;
340 if (size) *size = dc->attr->wnd_ext;
342 if (dc->attr->map_mode == MM_ISOTROPIC || dc->attr->map_mode == MM_ANISOTROPIC)
344 if (!x_num || !x_denom || !y_num || !y_denom)
346 release_dc_ptr( dc );
347 return FALSE;
350 dc->attr->wnd_ext.cx = (dc->attr->wnd_ext.cx * x_num) / x_denom;
351 dc->attr->wnd_ext.cy = (dc->attr->wnd_ext.cy * y_num) / y_denom;
352 if (dc->attr->wnd_ext.cx == 0) dc->attr->wnd_ext.cx = 1;
353 if (dc->attr->wnd_ext.cy == 0) dc->attr->wnd_ext.cy = 1;
354 if (dc->attr->map_mode == MM_ISOTROPIC) MAPPING_FixIsotropic( dc );
355 DC_UpdateXforms( dc );
358 release_dc_ptr( dc );
359 return TRUE;
363 /****************************************************************************
364 * NtGdiModifyWorldTransform (win32u.@)
366 BOOL WINAPI NtGdiModifyWorldTransform( HDC hdc, const XFORM *xform, DWORD mode )
368 BOOL ret = FALSE;
369 DC *dc;
371 if (!xform && mode != MWT_IDENTITY) return FALSE;
372 if ((dc = get_dc_ptr( hdc )))
374 switch (mode)
376 case MWT_IDENTITY:
377 dc->xformWorld2Wnd.eM11 = 1.0f;
378 dc->xformWorld2Wnd.eM12 = 0.0f;
379 dc->xformWorld2Wnd.eM21 = 0.0f;
380 dc->xformWorld2Wnd.eM22 = 1.0f;
381 dc->xformWorld2Wnd.eDx = 0.0f;
382 dc->xformWorld2Wnd.eDy = 0.0f;
383 ret = TRUE;
384 break;
385 case MWT_LEFTMULTIPLY:
386 combine_transform( &dc->xformWorld2Wnd, xform, &dc->xformWorld2Wnd );
387 ret = TRUE;
388 break;
389 case MWT_RIGHTMULTIPLY:
390 combine_transform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd, xform );
391 ret = TRUE;
392 break;
393 case MWT_SET:
394 ret = dc->attr->graphics_mode == GM_ADVANCED &&
395 xform->eM11 * xform->eM22 != xform->eM12 * xform->eM21;
396 if (ret) dc->xformWorld2Wnd = *xform;
397 break;
399 if (ret) DC_UpdateXforms( dc );
400 release_dc_ptr( dc );
402 return ret;
406 /***********************************************************************
407 * NtGdiSetVirtualResolution (win32u.@)
409 * Undocumented on msdn.
411 * Changes the values of screen size in pixels and millimeters used by
412 * the mapping mode functions.
414 * PARAMS
415 * hdc [I] Device context
416 * horz_res [I] Width in pixels (equivalent to HORZRES device cap).
417 * vert_res [I] Height in pixels (equivalent to VERTRES device cap).
418 * horz_size [I] Width in mm (equivalent to HORZSIZE device cap).
419 * vert_size [I] Height in mm (equivalent to VERTSIZE device cap).
421 * RETURNS
422 * TRUE if successful.
423 * FALSE if any (but not all) of the last four params are zero.
425 * NOTES
426 * This doesn't change the values returned by NtGdiGetDeviceCaps, just the
427 * scaling of the mapping modes.
429 * Calling with the last four params equal to zero sets the values
430 * back to their defaults obtained by calls to NtGdiGetDeviceCaps.
432 BOOL WINAPI NtGdiSetVirtualResolution( HDC hdc, DWORD horz_res, DWORD vert_res,
433 DWORD horz_size, DWORD vert_size )
435 DC * dc;
436 TRACE("(%p %d %d %d %d)\n", hdc, (int)horz_res, (int)vert_res, (int)horz_size, (int)vert_size);
438 if (!horz_res || !vert_res || !horz_size || !vert_size)
440 /* they must be all zero */
441 if (horz_res || vert_res || horz_size || vert_size) return FALSE;
444 dc = get_dc_ptr( hdc );
445 if (!dc) return FALSE;
447 dc->attr->virtual_res.cx = horz_res;
448 dc->attr->virtual_res.cy = vert_res;
449 dc->attr->virtual_size.cx = horz_size;
450 dc->attr->virtual_size.cy = vert_size;
452 release_dc_ptr( dc );
453 return TRUE;
456 void combine_transform( XFORM *result, const XFORM *xform1, const XFORM *xform2 )
458 XFORM r;
460 /* Create the result in a temporary XFORM, since result may be
461 * equal to xform1 or xform2 */
462 r.eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21;
463 r.eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22;
464 r.eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21;
465 r.eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22;
466 r.eDx = xform1->eDx * xform2->eM11 + xform1->eDy * xform2->eM21 + xform2->eDx;
467 r.eDy = xform1->eDx * xform2->eM12 + xform1->eDy * xform2->eM22 + xform2->eDy;
469 *result = r;