2 * MACDRV window/DC scrolling
4 * Copyright 1993 David W. Metcalfe
5 * Copyright 1995, 1996 Alex Korobka
6 * Copyright 2001 Alexandre Julliard
7 * Copyright 2011, 2013 Ken Thomases for CodeWeavers Inc.
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 WINE_DEFAULT_DEBUG_CHANNEL(scroll
);
32 static void dump_region(const char *p
, HRGN hrgn
)
40 TRACE("%s null region\n", p
);
43 if (!(size
= GetRegionData(hrgn
, 0, NULL
)))
45 if (!(data
= HeapAlloc(GetProcessHeap(), 0, size
))) return;
46 GetRegionData(hrgn
, size
, data
);
47 TRACE("%s %d rects:", p
, data
->rdh
.nCount
);
48 for (i
= 0, rect
= (RECT
*)data
->Buffer
; i
<20 && i
< data
->rdh
.nCount
; i
++, rect
++)
49 TRACE(" %s", wine_dbgstr_rect(rect
));
51 HeapFree(GetProcessHeap(), 0, data
);
55 /*************************************************************************
58 BOOL CDECL
macdrv_ScrollDC(HDC hdc
, INT dx
, INT dy
, const RECT
*lprcScroll
,
59 const RECT
*lprcClip
, HRGN hrgnUpdate
, LPRECT lprcUpdate
)
61 RECT rcSrc
, rcClip
, offset
;
62 INT dxdev
, dydev
, res
;
63 HRGN DstRgn
, clipRgn
, visrgn
;
65 TRACE("dx,dy %d,%d rcScroll %s rcClip %s hrgnUpdate %p lprcUpdate %p\n",
66 dx
, dy
, wine_dbgstr_rect(lprcScroll
), wine_dbgstr_rect(lprcClip
),
67 hrgnUpdate
, lprcUpdate
);
69 /* get the visible region */
70 visrgn
= CreateRectRgn(0, 0, 0, 0);
71 GetRandomRgn(hdc
, visrgn
, SYSRGN
);
72 if (!(GetVersion() & 0x80000000))
76 GetDCOrgEx(hdc
, &org
);
77 OffsetRgn(visrgn
, -org
.x
, -org
.y
);
80 /* intersect with the clipping Region if the DC has one */
81 clipRgn
= CreateRectRgn(0, 0, 0, 0);
82 if (GetClipRgn(hdc
, clipRgn
) != 1)
84 DeleteObject(clipRgn
);
88 CombineRgn(visrgn
, visrgn
, clipRgn
, RGN_AND
);
90 /* only those pixels in the scroll rectangle that remain in the clipping
91 * rect are scrolled. */
95 GetClipBox(hdc
, &rcClip
);
97 OffsetRect(&rcClip
, -dx
, -dy
);
98 IntersectRect(&rcSrc
, &rcSrc
, &rcClip
);
100 /* if an scroll rectangle is specified, only the pixels within that
101 * rectangle are scrolled */
103 IntersectRect(&rcSrc
, &rcSrc
, lprcScroll
);
105 /* now convert to device coordinates */
106 LPtoDP(hdc
, (LPPOINT
)&rcSrc
, 2);
107 TRACE("source rect: %s\n", wine_dbgstr_rect(&rcSrc
));
110 SetRect(&offset
, 0, 0, dx
, dy
);
111 LPtoDP(hdc
, (LPPOINT
)&offset
, 2);
112 dxdev
= offset
.right
- offset
.left
;
113 dydev
= offset
.bottom
- offset
.top
;
115 /* now intersect with the visible region to get the pixels that will
117 DstRgn
= CreateRectRgnIndirect(&rcSrc
);
118 res
= CombineRgn(DstRgn
, DstRgn
, visrgn
, RGN_AND
);
120 /* and translate, giving the destination region */
121 OffsetRgn(DstRgn
, dxdev
, dydev
);
122 if (TRACE_ON(scroll
)) dump_region("Destination scroll region: ", DstRgn
);
124 /* if there are any, do it */
125 if (res
> NULLREGION
)
128 /* clip to the destination region, so we can BitBlt with a simple
129 * bounding rectangle */
131 ExtSelectClipRgn(hdc
, DstRgn
, RGN_AND
);
133 SelectClipRgn(hdc
, DstRgn
);
134 GetRgnBox(DstRgn
, &rect
);
135 DPtoLP(hdc
, (LPPOINT
)&rect
, 2);
136 TRACE("destination rect: %s\n", wine_dbgstr_rect(&rect
));
138 BitBlt(hdc
, rect
.left
, rect
.top
,
139 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
,
140 hdc
, rect
.left
- dx
, rect
.top
- dy
, SRCCOPY
);
143 /* compute the update areas. This is the combined clip rectangle
144 * minus the scrolled region, and intersected with the visible
146 if (hrgnUpdate
|| lprcUpdate
)
148 HRGN hrgn
= hrgnUpdate
;
150 /* Intersect clip and scroll rectangles, allowing NULL values */
153 IntersectRect(&rcClip
, lprcClip
, lprcScroll
);
155 rcClip
= *lprcScroll
;
160 GetClipBox(hdc
, &rcClip
);
162 /* Convert the combined clip rectangle to device coordinates */
163 LPtoDP(hdc
, (LPPOINT
)&rcClip
, 2);
165 SetRectRgn(hrgn
, rcClip
.left
, rcClip
.top
, rcClip
.right
, rcClip
.bottom
);
167 hrgn
= CreateRectRgnIndirect(&rcClip
);
168 CombineRgn(hrgn
, hrgn
, visrgn
, RGN_AND
);
169 CombineRgn(hrgn
, hrgn
, DstRgn
, RGN_DIFF
);
170 if (TRACE_ON(scroll
)) dump_region("Update region: ", hrgn
);
173 GetRgnBox(hrgn
, lprcUpdate
);
174 /* Put the lprcUpdate in logical coordinates */
175 DPtoLP(hdc
, (LPPOINT
)lprcUpdate
, 2);
176 TRACE("returning lprcUpdate %s\n", wine_dbgstr_rect(lprcUpdate
));
182 /* restore original clipping region */
183 SelectClipRgn(hdc
, clipRgn
);
184 DeleteObject(visrgn
);
185 DeleteObject(DstRgn
);
186 if (clipRgn
) DeleteObject(clipRgn
);