riched20: Move underline drawing to a common function.
[wine.git] / dlls / winemac.drv / scroll.c
blobe8e7537cd45d4fa169c94edfe559dd82e8d719ff
1 /*
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
24 #include "config.h"
26 #include "macdrv.h"
27 #include "winuser.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(scroll);
32 static void dump_region(const char *p, HRGN hrgn)
34 DWORD i, size;
35 RGNDATA *data = NULL;
36 RECT *rect;
38 if (!hrgn)
40 TRACE("%s null region\n", p);
41 return;
43 if (!(size = GetRegionData(hrgn, 0, NULL)))
44 return;
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));
50 TRACE("\n");
51 HeapFree(GetProcessHeap(), 0, data);
55 /*************************************************************************
56 * ScrollDC (MACDRV.@)
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))
74 /* Window NT/2k/XP */
75 POINT org;
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);
85 clipRgn = NULL;
87 else
88 CombineRgn(visrgn, visrgn, clipRgn, RGN_AND);
90 /* only those pixels in the scroll rectangle that remain in the clipping
91 * rect are scrolled. */
92 if (lprcClip)
93 rcClip = *lprcClip;
94 else
95 GetClipBox(hdc, &rcClip);
96 rcSrc = 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 */
102 if (lprcScroll)
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));
109 /* also dx and dy */
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
116 * actually scroll */
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)
127 RECT rect ;
128 /* clip to the destination region, so we can BitBlt with a simple
129 * bounding rectangle */
130 if (clipRgn)
131 ExtSelectClipRgn(hdc, DstRgn, RGN_AND);
132 else
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
145 * region. */
146 if (hrgnUpdate || lprcUpdate)
148 HRGN hrgn = hrgnUpdate;
150 /* Intersect clip and scroll rectangles, allowing NULL values */
151 if (lprcScroll)
152 if (lprcClip)
153 IntersectRect(&rcClip, lprcClip, lprcScroll);
154 else
155 rcClip = *lprcScroll;
156 else
157 if (lprcClip)
158 rcClip = *lprcClip;
159 else
160 GetClipBox(hdc, &rcClip);
162 /* Convert the combined clip rectangle to device coordinates */
163 LPtoDP(hdc, (LPPOINT)&rcClip, 2);
164 if (hrgn)
165 SetRectRgn(hrgn, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom);
166 else
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);
171 if (lprcUpdate)
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));
178 if (!hrgnUpdate)
179 DeleteObject(hrgn);
182 /* restore original clipping region */
183 SelectClipRgn(hdc, clipRgn);
184 DeleteObject(visrgn);
185 DeleteObject(DstRgn);
186 if (clipRgn) DeleteObject(clipRgn);
187 return TRUE;