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
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
)
43 /* We want to deal with a positive divisor to simplify the logic. */
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
;
54 ret
= (((LONGLONG
)a
* b
) - (c
/ 2)) / c
;
56 if (ret
> 2147483647 || ret
< -2147483647) return -1;
60 static SIZE
get_dc_virtual_size( DC
*dc
)
62 SIZE ret
= dc
->attr
->virtual_size
;
66 ret
.cx
= NtGdiGetDeviceCaps( dc
->hSelf
, HORZSIZE
);
67 ret
.cy
= NtGdiGetDeviceCaps( dc
->hSelf
, VERTSIZE
);
72 static SIZE
get_dc_virtual_res( DC
*dc
)
74 SIZE ret
= dc
->attr
->virtual_res
;
78 ret
.cx
= NtGdiGetDeviceCaps( dc
->hSelf
, HORZRES
);
79 ret
.cy
= NtGdiGetDeviceCaps( dc
->hSelf
, VERTRES
);
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
));
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
;
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
))
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;
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
;
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
;
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
;
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
;
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
;
174 /* RTL layout is always MM_ANISOTROPIC */
175 if (!(dc
->attr
->layout
& LAYOUT_RTL
)) dc
->attr
->map_mode
= mode
;
176 DC_UpdateXforms( dc
);
180 /***********************************************************************
183 * Internal version of DPtoLP that takes a DC *.
185 BOOL
dp_to_lp( DC
*dc
, POINT
*points
, INT count
)
187 if (dc
->vport2WorldValid
)
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
);
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
);
215 if (!dc
) return FALSE
;
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
);
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
);
251 WARN( "invalid mode %x\n", mode
);
255 release_dc_ptr( dc
);
260 /***********************************************************************
263 * Internal version of LPtoDP that takes a DC *.
265 void lp_to_dp( DC
*dc
, POINT
*points
, INT 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
);
282 /***********************************************************************
283 * NtGdiComputeXformCoefficients (win32u.@)
285 BOOL WINAPI
NtGdiComputeXformCoefficients( HDC hdc
)
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
);
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
)
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
);
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
);
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
)
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
);
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
);
363 /****************************************************************************
364 * NtGdiModifyWorldTransform (win32u.@)
366 BOOL WINAPI
NtGdiModifyWorldTransform( HDC hdc
, const XFORM
*xform
, DWORD mode
)
371 if (!xform
&& mode
!= MWT_IDENTITY
) return FALSE
;
372 if ((dc
= get_dc_ptr( hdc
)))
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
;
385 case MWT_LEFTMULTIPLY
:
386 combine_transform( &dc
->xformWorld2Wnd
, xform
, &dc
->xformWorld2Wnd
);
389 case MWT_RIGHTMULTIPLY
:
390 combine_transform( &dc
->xformWorld2Wnd
, &dc
->xformWorld2Wnd
, xform
);
394 ret
= dc
->attr
->graphics_mode
== GM_ADVANCED
&&
395 xform
->eM11
* xform
->eM22
!= xform
->eM12
* xform
->eM21
;
396 if (ret
) dc
->xformWorld2Wnd
= *xform
;
399 if (ret
) DC_UpdateXforms( dc
);
400 release_dc_ptr( dc
);
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.
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).
422 * TRUE if successful.
423 * FALSE if any (but not all) of the last four params are zero.
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
)
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
);
456 void combine_transform( XFORM
*result
, const XFORM
*xform1
, const XFORM
*xform2
)
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
;