Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-gdi / region.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Client
3  * GDI Region Functions
4  *
5  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23
24 #include <freerdp/api.h>
25 #include <freerdp/freerdp.h>
26 #include <freerdp/gdi/gdi.h>
27
28 #include <freerdp/gdi/region.h>
29
30 /**
31  * Create a region from rectangular coordinates.\n
32  * @msdn{dd183514}
33  * @param nLeftRect x1
34  * @param nTopRect y1
35  * @param nRightRect x2
36  * @param nBottomRect y2
37  * @return new region
38  */
39
40 HGDI_RGN gdi_CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
41 {
42         HGDI_RGN hRgn = (HGDI_RGN) malloc(sizeof(GDI_RGN));
43         hRgn->objectType = GDIOBJECT_REGION;
44         hRgn->x = nLeftRect;
45         hRgn->y = nTopRect;
46         hRgn->w = nRightRect - nLeftRect + 1;
47         hRgn->h = nBottomRect - nTopRect + 1;
48         hRgn->null = 0;
49         return hRgn;
50 }
51
52 /**
53  * Create a new rectangle.
54  * @param xLeft x1
55  * @param yTop y1
56  * @param xRight x2
57  * @param yBottom y2
58  * @return new rectangle
59  */
60
61 HGDI_RECT gdi_CreateRect(int xLeft, int yTop, int xRight, int yBottom)
62 {
63         HGDI_RECT hRect = (HGDI_RECT) malloc(sizeof(GDI_RECT));
64         hRect->objectType = GDIOBJECT_RECT;
65         hRect->left = xLeft;
66         hRect->top = yTop;
67         hRect->right = xRight;
68         hRect->bottom = yBottom;
69         return hRect;
70 }
71
72 /**
73  * Convert a rectangle to a region.
74  * @param rect source rectangle
75  * @param rgn destination region
76  */
77
78 INLINE void gdi_RectToRgn(HGDI_RECT rect, HGDI_RGN rgn)
79 {
80         rgn->x = rect->left;
81         rgn->y = rect->top;
82         rgn->w = rect->right - rect->left + 1;
83         rgn->h = rect->bottom - rect->top + 1;
84 }
85
86 /**
87  * Convert rectangular coordinates to a region.
88  * @param left x1
89  * @param top y1
90  * @param right x2
91  * @param bottom y2
92  * @param rgn destination region
93  */
94
95 INLINE void gdi_CRectToRgn(int left, int top, int right, int bottom, HGDI_RGN rgn)
96 {
97         rgn->x = left;
98         rgn->y = top;
99         rgn->w = right - left + 1;
100         rgn->h = bottom - top + 1;
101 }
102
103 /**
104  * Convert a rectangle to region coordinates.
105  * @param rect source rectangle
106  * @param x x1
107  * @param y y1
108  * @param w width
109  * @param h height
110  */
111
112 INLINE void gdi_RectToCRgn(HGDI_RECT rect, int *x, int *y, int *w, int *h)
113 {
114         *x = rect->left;
115         *y = rect->top;
116         *w = rect->right - rect->left + 1;
117         *h = rect->bottom - rect->top + 1;
118 }
119
120 /**
121  * Convert rectangular coordinates to region coordinates.
122  * @param left x1
123  * @param top y1
124  * @param right x2
125  * @param bottom y2
126  * @param x x1
127  * @param y y1
128  * @param w width
129  * @param h height
130  */
131
132 INLINE void gdi_CRectToCRgn(int left, int top, int right, int bottom, int *x, int *y, int *w, int *h)
133 {
134         *x = left;
135         *y = top;
136         *w = right - left + 1;
137         *h = bottom - top + 1;
138 }
139
140 /**
141  * Convert a region to a rectangle.
142  * @param rgn source region
143  * @param rect destination rectangle
144  */
145
146 INLINE void gdi_RgnToRect(HGDI_RGN rgn, HGDI_RECT rect)
147 {
148         rect->left = rgn->x;
149         rect->top = rgn->y;
150         rect->right = rgn->x + rgn->w - 1;
151         rect->bottom = rgn->y + rgn->h - 1;
152 }
153
154 /**
155  * Convert region coordinates to a rectangle.
156  * @param x x1
157  * @param y y1
158  * @param w width
159  * @param h height
160  * @param rect destination rectangle
161  */
162
163 INLINE void gdi_CRgnToRect(int x, int y, int w, int h, HGDI_RECT rect)
164 {
165         rect->left = x;
166         rect->top = y;
167         rect->right = x + w - 1;
168         rect->bottom = y + h - 1;
169 }
170
171 /**
172  * Convert a region to rectangular coordinates.
173  * @param rgn source region
174  * @param left x1
175  * @param top y1
176  * @param right x2
177  * @param bottom y2
178  */
179
180 INLINE void gdi_RgnToCRect(HGDI_RGN rgn, int *left, int *top, int *right, int *bottom)
181 {
182         *left = rgn->x;
183         *top = rgn->y;
184         *right = rgn->x + rgn->w - 1;
185         *bottom = rgn->y + rgn->h - 1;
186 }
187
188 /**
189  * Convert region coordinates to rectangular coordinates.
190  * @param x x1
191  * @param y y1
192  * @param w width
193  * @param h height
194  * @param left x1
195  * @param top y1
196  * @param right x2
197  * @param bottom y2
198  */
199
200 INLINE void gdi_CRgnToCRect(int x, int y, int w, int h, int *left, int *top, int *right, int *bottom)
201 {
202         *left = x;
203         *top = y;
204         *right = x + w - 1;
205         *bottom = y + h - 1;
206 }
207
208 /**
209  * Check if copying would involve overlapping regions
210  * @param x x1
211  * @param y y1
212  * @param width width
213  * @param height height
214  * @param srcx source x1
215  * @param srcy source y1
216  * @return 1 if there is an overlap, 0 otherwise
217  */
218
219 INLINE int gdi_CopyOverlap(int x, int y, int width, int height, int srcx, int srcy)
220 {
221         GDI_RECT dst;
222         GDI_RECT src;
223
224         gdi_CRgnToRect(x, y, width, height, &dst);
225         gdi_CRgnToRect(srcx, srcy, width, height, &src);
226
227         return (dst.right > src.left && dst.left < src.right &&
228                 dst.bottom > src.top && dst.top < src.bottom) ? 1 : 0;
229 }
230
231 /**
232  * Set the coordinates of a given rectangle.\n
233  * @msdn{dd145085}
234  * @param rc rectangle
235  * @param xLeft x1
236  * @param yTop y1
237  * @param xRight x2
238  * @param yBottom y2
239  * @return 1 if successful, 0 otherwise
240  */
241
242 INLINE int gdi_SetRect(HGDI_RECT rc, int xLeft, int yTop, int xRight, int yBottom)
243 {
244         rc->left = xLeft;
245         rc->top = yTop;
246         rc->right = xRight;
247         rc->bottom = yBottom;
248         return 1;
249 }
250
251 /**
252  * Set the coordinates of a given region.
253  * @param hRgn region
254  * @param nXLeft x1
255  * @param nYLeft y1
256  * @param nWidth width
257  * @param nHeight height
258  * @return
259  */
260
261 INLINE int gdi_SetRgn(HGDI_RGN hRgn, int nXLeft, int nYLeft, int nWidth, int nHeight)
262 {
263         hRgn->x = nXLeft;
264         hRgn->y = nYLeft;
265         hRgn->w = nWidth;
266         hRgn->h = nHeight;
267         hRgn->null = 0;
268         return 0;
269 }
270
271 /**
272  * Convert rectangular coordinates to a region
273  * @param hRgn destination region
274  * @param nLeftRect x1
275  * @param nTopRect y1
276  * @param nRightRect x2
277  * @param nBottomRect y2
278  * @return
279  */
280
281 INLINE int gdi_SetRectRgn(HGDI_RGN hRgn, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect)
282 {
283         gdi_CRectToRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, hRgn);
284         hRgn->null = 0;
285         return 0;
286 }
287
288 /**
289  * Compare two regions for equality.\n
290  * @msdn{dd162700}
291  * @param hSrcRgn1 first region
292  * @param hSrcRgn2 second region
293  * @return 1 if both regions are equal, 0 otherwise
294  */
295
296 INLINE int gdi_EqualRgn(HGDI_RGN hSrcRgn1, HGDI_RGN hSrcRgn2)
297 {
298         if ((hSrcRgn1->x == hSrcRgn2->x) &&
299             (hSrcRgn1->y == hSrcRgn2->y) &&
300             (hSrcRgn1->w == hSrcRgn2->w) &&
301             (hSrcRgn1->h == hSrcRgn2->h))
302         {
303                 return 1;
304         }
305
306         return 0;
307 }
308
309 /**
310  * Copy coordinates from a rectangle to another rectangle
311  * @param dst destination rectangle
312  * @param src source rectangle
313  * @return 1 if successful, 0 otherwise
314  */
315
316 INLINE int gdi_CopyRect(HGDI_RECT dst, HGDI_RECT src)
317 {
318         dst->left = src->left;
319         dst->top = src->top;
320         dst->right = src->right;
321         dst->bottom = src->bottom;
322         return 1;
323 }
324
325 /**
326  * Check if a point is inside a rectangle.\n
327  * @msdn{dd162882}
328  * @param rc rectangle
329  * @param x point x position
330  * @param y point y position
331  * @return 1 if the point is inside, 0 otherwise
332  */
333
334 INLINE int gdi_PtInRect(HGDI_RECT rc, int x, int y)
335 {
336         /*
337          * points on the left and top sides are considered in,
338          * while points on the right and bottom sides are considered out
339          */
340
341         if (x >= rc->left && x <= rc->right)
342         {
343                 if (y >= rc->top && y <= rc->bottom)
344                 {
345                         return 1;
346                 }
347         }
348
349         return 0;
350 }
351
352 /**
353  * Invalidate a given region, such that it is redrawn on the next region update.\n
354  * @msdn{dd145003}
355  * @param hdc device context
356  * @param x x1
357  * @param y y1
358  * @param w width
359  * @param h height
360  * @return
361  */
362
363 INLINE int gdi_InvalidateRegion(HGDI_DC hdc, int x, int y, int w, int h)
364 {
365         GDI_RECT inv;
366         GDI_RECT rgn;
367         HGDI_RGN invalid;
368         HGDI_RGN cinvalid;
369
370         if (hdc->hwnd == NULL)
371                 return 0;
372
373         if (hdc->hwnd->invalid == NULL)
374                 return 0;
375
376         cinvalid = hdc->hwnd->cinvalid;
377
378         if (hdc->hwnd->ninvalid + 1 > hdc->hwnd->count)
379         {
380                 hdc->hwnd->count *= 2;
381                 cinvalid = (HGDI_RGN) realloc(cinvalid, sizeof(GDI_RGN) * (hdc->hwnd->count));
382         }
383
384         gdi_SetRgn(&cinvalid[hdc->hwnd->ninvalid++], x, y, w, h);
385         hdc->hwnd->cinvalid = cinvalid;
386
387         invalid = hdc->hwnd->invalid;
388
389         if (invalid->null)
390         {
391                 invalid->x = x;
392                 invalid->y = y;
393                 invalid->w = w;
394                 invalid->h = h;
395                 invalid->null = 0;
396                 return 0;
397         }
398
399         gdi_CRgnToRect(x, y, w, h, &rgn);
400         gdi_RgnToRect(invalid, &inv);
401
402         if (rgn.left < 0)
403                 rgn.left = 0;
404
405         if (rgn.top < 0)
406                 rgn.top = 0;
407
408         if (rgn.left < inv.left)
409                 inv.left = rgn.left;
410
411         if (rgn.top < inv.top)
412                 inv.top = rgn.top;
413
414         if (rgn.right > inv.right)
415                 inv.right = rgn.right;
416
417         if (rgn.bottom > inv.bottom)
418                 inv.bottom = rgn.bottom;
419
420         gdi_RectToRgn(&inv, invalid);
421
422         return 0;
423 }