Changes for multiple window support
[reactos.git] / reactos / subsys / win32k / objects / region.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: region.c,v 1.29 2003/07/17 07:49:15 gvg Exp $ */
20 #undef WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 #include <ddk/ntddk.h>
23 #include <internal/safe.h>
24 #include <win32k/float.h>
25 #include <win32k/dc.h>
26 #include <win32k/bitmaps.h>
27 #include <win32k/region.h>
28 #include <win32k/cliprgn.h>
29 #include <win32k/brush.h>
30 #include <include/rect.h>
31 #include <include/object.h>
32 #include <include/inteng.h>
33 #include <include/error.h>
34
35 #define NDEBUG
36 #include <win32k/debug1.h>
37
38 BOOL STDCALL
39 IntEngPaint(IN SURFOBJ *Surface,IN CLIPOBJ *ClipRegion,IN BRUSHOBJ *Brush,IN POINTL *BrushOrigin,
40 IN MIX Mix);
41
42 // Internal Functions
43
44 #define EMPTY_REGION(pReg) { \
45 (pReg)->rdh.nCount = 0; \
46 (pReg)->rdh.rcBound.left = (pReg)->rdh.rcBound.top = 0; \
47 (pReg)->rdh.rcBound.right = (pReg)->rdh.rcBound.bottom = 0; \
48 (pReg)->rdh.iType = NULLREGION; \
49 }
50
51 #define REGION_NOT_EMPTY(pReg) pReg->rdh.nCount
52
53 #define INRECT(r, x, y) \
54 ( ( ((r).right > x)) && \
55 ( ((r).left <= x)) && \
56 ( ((r).bottom > y)) && \
57 ( ((r).top <= y)) )
58
59 /* 1 if two RECTs overlap.
60 * 0 if two RECTs do not overlap.
61 */
62 #define EXTENTCHECK(r1, r2) \
63 ((r1)->right > (r2)->left && \
64 (r1)->left < (r2)->right && \
65 (r1)->bottom > (r2)->top && \
66 (r1)->top < (r2)->bottom)
67
68 /*
69 * Check to see if there is enough memory in the present region.
70 */
71 static inline int xmemcheck(ROSRGNDATA *reg, LPRECT *rect, LPRECT *firstrect ) {
72 if ( (reg->rdh.nCount+1)*sizeof( RECT ) >= reg->rdh.nRgnSize ) {
73 PRECT temp;
74 temp = ExAllocatePool( PagedPool, (2 * (reg->rdh.nRgnSize)));
75
76 if (temp == 0)
77 return 0;
78 RtlCopyMemory( temp, *firstrect, reg->rdh.nRgnSize );
79 reg->rdh.nRgnSize *= 2;
80 ExFreePool( *firstrect );
81 *firstrect = temp;
82 *rect = (*firstrect)+reg->rdh.nCount;
83 }
84 return 1;
85 }
86
87 #define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(LPRECT *)&(firstrect))
88
89 typedef void FASTCALL (*overlapProcp)(PROSRGNDATA, PRECT, PRECT, PRECT, PRECT, INT, INT);
90 typedef void FASTCALL (*nonOverlapProcp)(PROSRGNDATA, PRECT, PRECT, INT, INT);
91
92 // Number of points to buffer before sending them off to scanlines() : Must be an even number
93 #define NUMPTSTOBUFFER 200
94
95 #define RGN_DEFAULT_RECTS 2
96
97 // used to allocate buffers for points and link the buffers together
98
99 typedef struct _POINTBLOCK {
100 POINT pts[NUMPTSTOBUFFER];
101 struct _POINTBLOCK *next;
102 } POINTBLOCK;
103
104 static BOOL FASTCALL REGION_CopyRegion(PROSRGNDATA dst, PROSRGNDATA src)
105 {
106 if(dst != src) // don't want to copy to itself
107 {
108 if (dst->rdh.nRgnSize < src->rdh.nCount * sizeof(RECT))
109 {
110 PCHAR temp;
111
112 temp = ExAllocatePool(PagedPool, src->rdh.nCount * sizeof(RECT) );
113 if( !temp )
114 return FALSE;
115
116 if( dst->Buffer )
117 ExFreePool( dst->Buffer ); //free the old buffer
118 dst->Buffer = temp;
119 dst->rdh.nRgnSize = src->rdh.nCount * sizeof(RECT); //size of region buffer
120 }
121 dst->rdh.nCount = src->rdh.nCount; //number of rectangles present in Buffer
122 dst->rdh.rcBound.left = src->rdh.rcBound.left;
123 dst->rdh.rcBound.top = src->rdh.rcBound.top;
124 dst->rdh.rcBound.right = src->rdh.rcBound.right;
125 dst->rdh.rcBound.bottom = src->rdh.rcBound.bottom;
126 dst->rdh.iType = src->rdh.iType;
127 RtlCopyMemory(dst->Buffer, src->Buffer, (int)(src->rdh.nCount * sizeof(RECT)));
128 }
129 return TRUE;
130 }
131
132 static void FASTCALL REGION_SetExtents (ROSRGNDATA *pReg)
133 {
134 RECT *pRect, *pRectEnd, *pExtents;
135
136 if (pReg->rdh.nCount == 0)
137 {
138 pReg->rdh.rcBound.left = 0;
139 pReg->rdh.rcBound.top = 0;
140 pReg->rdh.rcBound.right = 0;
141 pReg->rdh.rcBound.bottom = 0;
142 return;
143 }
144
145 pExtents = &pReg->rdh.rcBound;
146 pRect = (PRECT)pReg->Buffer;
147 pRectEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount - 1;
148
149 /*
150 * Since pRect is the first rectangle in the region, it must have the
151 * smallest top and since pRectEnd is the last rectangle in the region,
152 * it must have the largest bottom, because of banding. Initialize left and
153 * right from pRect and pRectEnd, resp., as good things to initialize them
154 * to...
155 */
156 pExtents->left = pRect->left;
157 pExtents->top = pRect->top;
158 pExtents->right = pRectEnd->right;
159 pExtents->bottom = pRectEnd->bottom;
160
161 while (pRect <= pRectEnd)
162 {
163 if (pRect->left < pExtents->left)
164 pExtents->left = pRect->left;
165 if (pRect->right > pExtents->right)
166 pExtents->right = pRect->right;
167 pRect++;
168 }
169 }
170
171
172 /***********************************************************************
173 * REGION_CropAndOffsetRegion
174 */
175 static BOOL FASTCALL REGION_CropAndOffsetRegion(const PPOINT off, const PRECT rect, PROSRGNDATA rgnSrc, PROSRGNDATA rgnDst)
176 {
177 if(!rect) // just copy and offset
178 {
179 PRECT xrect;
180 if(rgnDst == rgnSrc)
181 {
182 if(off->x || off->y)
183 xrect = (PRECT)rgnDst->Buffer;
184 else
185 return TRUE;
186 }
187 else{
188 xrect = ExAllocatePool(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT));
189 if( rgnDst->Buffer )
190 ExFreePool( rgnDst->Buffer ); //free the old buffer. will be assigned to xrect below.
191 }
192
193 if(xrect)
194 {
195 INT i;
196
197 if(rgnDst != rgnSrc)
198 RtlCopyMemory(rgnDst, rgnSrc, sizeof(ROSRGNDATA));
199
200 if(off->x || off->y)
201 {
202 for(i = 0; i < rgnDst->rdh.nCount; i++)
203 {
204 xrect[i].left = ((PRECT)rgnSrc->Buffer + i)->left + off->x;
205 xrect[i].right = ((PRECT)rgnSrc->Buffer + i)->right + off->x;
206 xrect[i].top = ((PRECT)rgnSrc->Buffer + i)->top + off->y;
207 xrect[i].bottom = ((PRECT)rgnSrc->Buffer + i)->bottom + off->y;
208 }
209 rgnDst->rdh.rcBound.left += off->x;
210 rgnDst->rdh.rcBound.right += off->x;
211 rgnDst->rdh.rcBound.top += off->y;
212 rgnDst->rdh.rcBound.bottom += off->y;
213 }
214 else
215 RtlCopyMemory(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount * sizeof(RECT));
216
217 rgnDst->Buffer = (char*)xrect;
218 } else
219 return FALSE;
220 }
221 else if ((rect->left >= rect->right) ||
222 (rect->top >= rect->bottom) ||
223 !EXTENTCHECK(rect, &rgnSrc->rdh.rcBound))
224 {
225 goto empty;
226 }
227 else // region box and clipping rect appear to intersect
228 {
229 PRECT lpr, rpr;
230 INT i, j, clipa, clipb;
231 INT left = rgnSrc->rdh.rcBound.right + off->x;
232 INT right = rgnSrc->rdh.rcBound.left + off->x;
233
234 for(clipa = 0; ((PRECT)rgnSrc->Buffer + clipa)->bottom <= rect->top; clipa++)
235 //region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
236 ; // skip bands above the clipping rectangle
237
238 for(clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++)
239 if(((PRECT)rgnSrc->Buffer + clipb)->top >= rect->bottom)
240 break; // and below it
241
242 // clipa - index of the first rect in the first intersecting band
243 // clipb - index of the last rect in the last intersecting band
244
245 if((rgnDst != rgnSrc) && (rgnDst->rdh.nCount < (i = (clipb - clipa))))
246 {
247 PCHAR temp;
248 temp = ExAllocatePool( PagedPool, i * sizeof(RECT) );
249 if(!temp)
250 return FALSE;
251
252 if( rgnDst->Buffer )
253 ExFreePool( rgnDst->Buffer ); //free the old buffer
254 (PRECT)rgnDst->Buffer = temp;
255 rgnDst->rdh.nCount = i;
256 rgnDst->rdh.nRgnSize = i * sizeof(RECT);
257 }
258
259 for(i = clipa, j = 0; i < clipb ; i++)
260 {
261 // i - src index, j - dst index, j is always <= i for obvious reasons
262
263 lpr = (PRECT)rgnSrc->Buffer + i;
264
265 if(lpr->left < rect->right && lpr->right > rect->left)
266 {
267 rpr = (PRECT)rgnDst->Buffer + j;
268
269 rpr->top = lpr->top + off->y;
270 rpr->bottom = lpr->bottom + off->y;
271 rpr->left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
272 rpr->right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
273
274 if(rpr->left < left) left = rpr->left;
275 if(rpr->right > right) right = rpr->right;
276
277 j++;
278 }
279 }
280
281 if(j == 0) goto empty;
282
283 rgnDst->rdh.rcBound.left = left;
284 rgnDst->rdh.rcBound.right = right;
285
286 left = rect->top + off->y;
287 right = rect->bottom + off->y;
288
289 rgnDst->rdh.nCount = j--;
290 for(i = 0; i <= j; i++) // fixup top band
291 if(((PRECT)rgnDst->Buffer + i)->top < left)
292 ((PRECT)rgnDst->Buffer + i)->top = left;
293 else
294 break;
295
296 for(i = j; i >= 0; i--) // fixup bottom band
297 if(((PRECT)rgnDst->Buffer + i)->bottom > right)
298 ((PRECT)rgnDst->Buffer + i)->bottom = right;
299 else
300 break;
301
302 rgnDst->rdh.rcBound.top = ((PRECT)rgnDst->Buffer)->top;
303 rgnDst->rdh.rcBound.bottom = ((PRECT)rgnDst->Buffer + j)->bottom;
304
305 rgnDst->rdh.iType = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
306 }
307
308 return TRUE;
309
310 empty:
311 if(!rgnDst->Buffer)
312 {
313 rgnDst->Buffer = (char*)ExAllocatePool(PagedPool, RGN_DEFAULT_RECTS * sizeof(RECT));
314 if(rgnDst->Buffer){
315 rgnDst->rdh.nCount = RGN_DEFAULT_RECTS;
316 rgnDst->rdh.nRgnSize = RGN_DEFAULT_RECTS * sizeof(RECT);
317 }
318 else
319 return FALSE;
320 }
321 EMPTY_REGION(rgnDst);
322 return TRUE;
323 }
324
325 /*!
326 * \param
327 * hSrc: Region to crop and offset.
328 * lpRect: Clipping rectangle. Can be NULL (no clipping).
329 * lpPt: Points to offset the cropped region. Can be NULL (no offset).
330 *
331 * hDst: Region to hold the result (a new region is created if it's 0).
332 * Allowed to be the same region as hSrc in which case everything
333 * will be done in place, with no memory reallocations.
334 *
335 * \return hDst if success, 0 otherwise.
336 */
337 HRGN STDCALL REGION_CropRgn(HRGN hDst, HRGN hSrc, const PRECT lpRect, PPOINT lpPt)
338 {
339 PROSRGNDATA objSrc, rgnDst;
340 HRGN hNewDst, hRet = NULL;
341 GDIMULTILOCK Lock[2] = {{hDst, 0, GO_REGION_MAGIC}, {hSrc, 0, GO_REGION_MAGIC}};
342
343 if( !hDst ){
344 if( !( hNewDst = RGNDATA_AllocRgn(1) ) ){
345 return 0;
346 }
347 Lock[0].hObj = hNewDst;
348 }
349
350 GDIOBJ_LockMultipleObj(Lock, 2);
351 rgnDst = Lock[0].pObj;
352 objSrc = Lock[1].pObj;
353
354 if( objSrc && rgnDst )
355 {
356 if(rgnDst)
357 {
358 POINT pt = { 0, 0 };
359
360 if(!lpPt)
361 lpPt = &pt;
362
363 if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE)
364 { // ve failed cleanup and return
365 hRet = NULL;
366 }
367 else{ // ve are fine. unlock the correct pointer and return correct handle
368 hRet = Lock[0].hObj;
369 }
370 }
371 }
372 GDIOBJ_UnlockMultipleObj(Lock, 2);
373 return hRet;
374 }
375
376 /*!
377 * Attempt to merge the rects in the current band with those in the
378 * previous one. Used only by REGION_RegionOp.
379 *
380 * Results:
381 * The new index for the previous band.
382 *
383 * \note Side Effects:
384 * If coalescing takes place:
385 * - rectangles in the previous band will have their bottom fields
386 * altered.
387 * - pReg->numRects will be decreased.
388 *
389 */
390 static INT FASTCALL REGION_Coalesce (
391 PROSRGNDATA pReg, /* Region to coalesce */
392 INT prevStart, /* Index of start of previous band */
393 INT curStart /* Index of start of current band */
394 ) {
395 RECT *pPrevRect; /* Current rect in previous band */
396 RECT *pCurRect; /* Current rect in current band */
397 RECT *pRegEnd; /* End of region */
398 INT curNumRects; /* Number of rectangles in current band */
399 INT prevNumRects; /* Number of rectangles in previous band */
400 INT bandtop; /* top coordinate for current band */
401
402 pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
403 pPrevRect = (PRECT)pReg->Buffer + prevStart;
404 prevNumRects = curStart - prevStart;
405
406 /*
407 * Figure out how many rectangles are in the current band. Have to do
408 * this because multiple bands could have been added in REGION_RegionOp
409 * at the end when one region has been exhausted.
410 */
411 pCurRect = (PRECT)pReg->Buffer + curStart;
412 bandtop = pCurRect->top;
413 for (curNumRects = 0;
414 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
415 curNumRects++)
416 {
417 pCurRect++;
418 }
419
420 if (pCurRect != pRegEnd)
421 {
422 /*
423 * If more than one band was added, we have to find the start
424 * of the last band added so the next coalescing job can start
425 * at the right place... (given when multiple bands are added,
426 * this may be pointless -- see above).
427 */
428 pRegEnd--;
429 while ((pRegEnd-1)->top == pRegEnd->top)
430 {
431 pRegEnd--;
432 }
433 curStart = pRegEnd - (PRECT)pReg->Buffer;
434 pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
435 }
436
437 if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
438 pCurRect -= curNumRects;
439 /*
440 * The bands may only be coalesced if the bottom of the previous
441 * matches the top scanline of the current.
442 */
443 if (pPrevRect->bottom == pCurRect->top)
444 {
445 /*
446 * Make sure the bands have rects in the same places. This
447 * assumes that rects have been added in such a way that they
448 * cover the most area possible. I.e. two rects in a band must
449 * have some horizontal space between them.
450 */
451 do
452 {
453 if ((pPrevRect->left != pCurRect->left) ||
454 (pPrevRect->right != pCurRect->right))
455 {
456 /*
457 * The bands don't line up so they can't be coalesced.
458 */
459 return (curStart);
460 }
461 pPrevRect++;
462 pCurRect++;
463 prevNumRects -= 1;
464 } while (prevNumRects != 0);
465
466 pReg->rdh.nCount -= curNumRects;
467 pCurRect -= curNumRects;
468 pPrevRect -= curNumRects;
469
470 /*
471 * The bands may be merged, so set the bottom of each rect
472 * in the previous band to that of the corresponding rect in
473 * the current band.
474 */
475 do
476 {
477 pPrevRect->bottom = pCurRect->bottom;
478 pPrevRect++;
479 pCurRect++;
480 curNumRects -= 1;
481 } while (curNumRects != 0);
482
483 /*
484 * If only one band was added to the region, we have to backup
485 * curStart to the start of the previous band.
486 *
487 * If more than one band was added to the region, copy the
488 * other bands down. The assumption here is that the other bands
489 * came from the same region as the current one and no further
490 * coalescing can be done on them since it's all been done
491 * already... curStart is already in the right place.
492 */
493 if (pCurRect == pRegEnd)
494 {
495 curStart = prevStart;
496 }
497 else
498 {
499 do
500 {
501 *pPrevRect++ = *pCurRect++;
502 } while (pCurRect != pRegEnd);
503 }
504 }
505 }
506 return (curStart);
507 }
508
509 /*!
510 * Apply an operation to two regions. Called by REGION_Union,
511 * REGION_Inverse, REGION_Subtract, REGION_Intersect...
512 *
513 * Results:
514 * None.
515 *
516 * Side Effects:
517 * The new region is overwritten.
518 *
519 *\note The idea behind this function is to view the two regions as sets.
520 * Together they cover a rectangle of area that this function divides
521 * into horizontal bands where points are covered only by one region
522 * or by both. For the first case, the nonOverlapFunc is called with
523 * each the band and the band's upper and lower extents. For the
524 * second, the overlapFunc is called to process the entire band. It
525 * is responsible for clipping the rectangles in the band, though
526 * this function provides the boundaries.
527 * At the end of each band, the new region is coalesced, if possible,
528 * to reduce the number of rectangles in the region.
529 *
530 */
531 static void FASTCALL REGION_RegionOp(
532 ROSRGNDATA *newReg, /* Place to store result */
533 ROSRGNDATA *reg1, /* First region in operation */
534 ROSRGNDATA *reg2, /* 2nd region in operation */
535 overlapProcp overlapFunc, /* Function to call for over-lapping bands */
536 nonOverlapProcp nonOverlap1Func, /* Function to call for non-overlapping bands in region 1 */
537 nonOverlapProcp nonOverlap2Func /* Function to call for non-overlapping bands in region 2 */
538 ) {
539 RECT *r1; /* Pointer into first region */
540 RECT *r2; /* Pointer into 2d region */
541 RECT *r1End; /* End of 1st region */
542 RECT *r2End; /* End of 2d region */
543 INT ybot; /* Bottom of intersection */
544 INT ytop; /* Top of intersection */
545 RECT *oldRects; /* Old rects for newReg */
546 INT prevBand; /* Index of start of
547 * previous band in newReg */
548 INT curBand; /* Index of start of current
549 * band in newReg */
550 RECT *r1BandEnd; /* End of current band in r1 */
551 RECT *r2BandEnd; /* End of current band in r2 */
552 INT top; /* Top of non-overlapping band */
553 INT bot; /* Bottom of non-overlapping band */
554
555 /*
556 * Initialization:
557 * set r1, r2, r1End and r2End appropriately, preserve the important
558 * parts of the destination region until the end in case it's one of
559 * the two source regions, then mark the "new" region empty, allocating
560 * another array of rectangles for it to use.
561 */
562 r1 = (PRECT)reg1->Buffer;
563 r2 = (PRECT)reg2->Buffer;
564 r1End = r1 + reg1->rdh.nCount;
565 r2End = r2 + reg2->rdh.nCount;
566
567
568 /*
569 * newReg may be one of the src regions so we can't empty it. We keep a
570 * note of its rects pointer (so that we can free them later), preserve its
571 * extents and simply set numRects to zero.
572 */
573
574 oldRects = (PRECT)newReg->Buffer;
575 newReg->rdh.nCount = 0;
576
577 /*
578 * Allocate a reasonable number of rectangles for the new region. The idea
579 * is to allocate enough so the individual functions don't need to
580 * reallocate and copy the array, which is time consuming, yet we don't
581 * have to worry about using too much memory. I hope to be able to
582 * nuke the Xrealloc() at the end of this function eventually.
583 */
584 newReg->rdh.nRgnSize = max(reg1->rdh.nCount,reg2->rdh.nCount) * 2 * sizeof(RECT);
585
586 if (! (newReg->Buffer = ExAllocatePool( PagedPool, newReg->rdh.nRgnSize )))
587 {
588 newReg->rdh.nRgnSize = 0;
589 return;
590 }
591
592 /*
593 * Initialize ybot and ytop.
594 * In the upcoming loop, ybot and ytop serve different functions depending
595 * on whether the band being handled is an overlapping or non-overlapping
596 * band.
597 * In the case of a non-overlapping band (only one of the regions
598 * has points in the band), ybot is the bottom of the most recent
599 * intersection and thus clips the top of the rectangles in that band.
600 * ytop is the top of the next intersection between the two regions and
601 * serves to clip the bottom of the rectangles in the current band.
602 * For an overlapping band (where the two regions intersect), ytop clips
603 * the top of the rectangles of both regions and ybot clips the bottoms.
604 */
605 if (reg1->rdh.rcBound.top < reg2->rdh.rcBound.top)
606 ybot = reg1->rdh.rcBound.top;
607 else
608 ybot = reg2->rdh.rcBound.top;
609
610 /*
611 * prevBand serves to mark the start of the previous band so rectangles
612 * can be coalesced into larger rectangles. qv. miCoalesce, above.
613 * In the beginning, there is no previous band, so prevBand == curBand
614 * (curBand is set later on, of course, but the first band will always
615 * start at index 0). prevBand and curBand must be indices because of
616 * the possible expansion, and resultant moving, of the new region's
617 * array of rectangles.
618 */
619 prevBand = 0;
620
621 do
622 {
623 curBand = newReg->rdh.nCount;
624
625 /*
626 * This algorithm proceeds one source-band (as opposed to a
627 * destination band, which is determined by where the two regions
628 * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
629 * rectangle after the last one in the current band for their
630 * respective regions.
631 */
632 r1BandEnd = r1;
633 while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top))
634 {
635 r1BandEnd++;
636 }
637
638 r2BandEnd = r2;
639 while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top))
640 {
641 r2BandEnd++;
642 }
643
644 /*
645 * First handle the band that doesn't intersect, if any.
646 *
647 * Note that attention is restricted to one band in the
648 * non-intersecting region at once, so if a region has n
649 * bands between the current position and the next place it overlaps
650 * the other, this entire loop will be passed through n times.
651 */
652 if (r1->top < r2->top)
653 {
654 top = max(r1->top,ybot);
655 bot = min(r1->bottom,r2->top);
656
657 if ((top != bot) && (nonOverlap1Func != NULL))
658 {
659 (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
660 }
661
662 ytop = r2->top;
663 }
664 else if (r2->top < r1->top)
665 {
666 top = max(r2->top,ybot);
667 bot = min(r2->bottom,r1->top);
668
669 if ((top != bot) && (nonOverlap2Func != NULL))
670 {
671 (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
672 }
673
674 ytop = r1->top;
675 }
676 else
677 {
678 ytop = r1->top;
679 }
680
681 /*
682 * If any rectangles got added to the region, try and coalesce them
683 * with rectangles from the previous band. Note we could just do
684 * this test in miCoalesce, but some machines incur a not
685 * inconsiderable cost for function calls, so...
686 */
687 if (newReg->rdh.nCount != curBand)
688 {
689 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
690 }
691
692 /*
693 * Now see if we've hit an intersecting band. The two bands only
694 * intersect if ybot > ytop
695 */
696 ybot = min(r1->bottom, r2->bottom);
697 curBand = newReg->rdh.nCount;
698 if (ybot > ytop)
699 {
700 (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
701 }
702
703 if (newReg->rdh.nCount != curBand)
704 {
705 prevBand = REGION_Coalesce (newReg, prevBand, curBand);
706 }
707
708 /*
709 * If we've finished with a band (bottom == ybot) we skip forward
710 * in the region to the next band.
711 */
712 if (r1->bottom == ybot)
713 {
714 r1 = r1BandEnd;
715 }
716 if (r2->bottom == ybot)
717 {
718 r2 = r2BandEnd;
719 }
720 } while ((r1 != r1End) && (r2 != r2End));
721
722 /*
723 * Deal with whichever region still has rectangles left.
724 */
725 curBand = newReg->rdh.nCount;
726 if (r1 != r1End)
727 {
728 if (nonOverlap1Func != NULL)
729 {
730 do
731 {
732 r1BandEnd = r1;
733 while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
734 {
735 r1BandEnd++;
736 }
737 (* nonOverlap1Func) (newReg, r1, r1BandEnd,
738 max(r1->top,ybot), r1->bottom);
739 r1 = r1BandEnd;
740 } while (r1 != r1End);
741 }
742 }
743 else if ((r2 != r2End) && (nonOverlap2Func != NULL))
744 {
745 do
746 {
747 r2BandEnd = r2;
748 while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
749 {
750 r2BandEnd++;
751 }
752 (* nonOverlap2Func) (newReg, r2, r2BandEnd,
753 max(r2->top,ybot), r2->bottom);
754 r2 = r2BandEnd;
755 } while (r2 != r2End);
756 }
757
758 if (newReg->rdh.nCount != curBand)
759 {
760 (void) REGION_Coalesce (newReg, prevBand, curBand);
761 }
762
763 /*
764 * A bit of cleanup. To keep regions from growing without bound,
765 * we shrink the array of rectangles to match the new number of
766 * rectangles in the region. This never goes to 0, however...
767 *
768 * Only do this stuff if the number of rectangles allocated is more than
769 * twice the number of rectangles in the region (a simple optimization...).
770 */
771 if ((2 * newReg->rdh.nCount*sizeof(RECT) < newReg->rdh.nRgnSize && (newReg->rdh.nCount > 2)))
772 {
773 if (REGION_NOT_EMPTY(newReg))
774 {
775 RECT *prev_rects = (PRECT)newReg->Buffer;
776 newReg->Buffer = ExAllocatePool( PagedPool, newReg->rdh.nCount*sizeof(RECT) );
777
778 if (! newReg->Buffer)
779 newReg->Buffer = (char*)prev_rects;
780 else{
781 newReg->rdh.nRgnSize = newReg->rdh.nCount*sizeof(RECT);
782 RtlCopyMemory( newReg->Buffer, prev_rects, newReg->rdh.nRgnSize );
783 ExFreePool( prev_rects );
784 }
785 }
786 else
787 {
788 /*
789 * No point in doing the extra work involved in an Xrealloc if
790 * the region is empty
791 */
792 newReg->rdh.nRgnSize = sizeof(RECT);
793 ExFreePool( newReg->Buffer );
794 newReg->Buffer = ExAllocatePool( PagedPool, sizeof(RECT) );
795 ASSERT( newReg->Buffer );
796 }
797 }
798
799 if( newReg->rdh.nCount == 0 )
800 newReg->rdh.iType = NULLREGION;
801 else
802 newReg->rdh.iType = (newReg->rdh.nCount > 1)? COMPLEXREGION : SIMPLEREGION;
803
804 ExFreePool( oldRects );
805 return;
806 }
807
808 /***********************************************************************
809 * Region Intersection
810 ***********************************************************************/
811
812
813 /*!
814 * Handle an overlapping band for REGION_Intersect.
815 *
816 * Results:
817 * None.
818 *
819 * \note Side Effects:
820 * Rectangles may be added to the region.
821 *
822 */
823 static void FASTCALL REGION_IntersectO(ROSRGNDATA *pReg, RECT *r1, RECT *r1End,
824 RECT *r2, RECT *r2End, INT top, INT bottom)
825
826 {
827 INT left, right;
828 RECT *pNextRect;
829
830 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
831
832 while ((r1 != r1End) && (r2 != r2End))
833 {
834 left = max(r1->left, r2->left);
835 right = min(r1->right, r2->right);
836
837 /*
838 * If there's any overlap between the two rectangles, add that
839 * overlap to the new region.
840 * There's no need to check for subsumption because the only way
841 * such a need could arise is if some region has two rectangles
842 * right next to each other. Since that should never happen...
843 */
844 if (left < right)
845 {
846 MEMCHECK(pReg, pNextRect, pReg->Buffer);
847 pNextRect->left = left;
848 pNextRect->top = top;
849 pNextRect->right = right;
850 pNextRect->bottom = bottom;
851 pReg->rdh.nCount += 1;
852 pNextRect++;
853 }
854
855 /*
856 * Need to advance the pointers. Shift the one that extends
857 * to the right the least, since the other still has a chance to
858 * overlap with that region's next rectangle, if you see what I mean.
859 */
860 if (r1->right < r2->right)
861 {
862 r1++;
863 }
864 else if (r2->right < r1->right)
865 {
866 r2++;
867 }
868 else
869 {
870 r1++;
871 r2++;
872 }
873 }
874 return;
875 }
876
877 /***********************************************************************
878 * REGION_IntersectRegion
879 */
880 static void FASTCALL REGION_IntersectRegion(ROSRGNDATA *newReg, ROSRGNDATA *reg1,
881 ROSRGNDATA *reg2)
882 {
883 /* check for trivial reject */
884 if ( (!(reg1->rdh.nCount)) || (!(reg2->rdh.nCount)) ||
885 (!EXTENTCHECK(&reg1->rdh.rcBound, &reg2->rdh.rcBound)))
886 newReg->rdh.nCount = 0;
887 else
888 REGION_RegionOp (newReg, reg1, reg2,
889 REGION_IntersectO, NULL, NULL);
890
891 /*
892 * Can't alter newReg's extents before we call miRegionOp because
893 * it might be one of the source regions and miRegionOp depends
894 * on the extents of those regions being the same. Besides, this
895 * way there's no checking against rectangles that will be nuked
896 * due to coalescing, so we have to examine fewer rectangles.
897 */
898
899 REGION_SetExtents(newReg);
900 }
901
902 /***********************************************************************
903 * Region Union
904 ***********************************************************************/
905
906 /*!
907 * Handle a non-overlapping band for the union operation. Just
908 * Adds the rectangles into the region. Doesn't have to check for
909 * subsumption or anything.
910 *
911 * Results:
912 * None.
913 *
914 * \note Side Effects:
915 * pReg->numRects is incremented and the final rectangles overwritten
916 * with the rectangles we're passed.
917 *
918 */
919 static void FASTCALL REGION_UnionNonO (ROSRGNDATA *pReg, RECT *r, RECT *rEnd,
920 INT top, INT bottom)
921 {
922 RECT *pNextRect;
923
924 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
925
926 while (r != rEnd)
927 {
928 MEMCHECK(pReg, pNextRect, pReg->Buffer);
929 pNextRect->left = r->left;
930 pNextRect->top = top;
931 pNextRect->right = r->right;
932 pNextRect->bottom = bottom;
933 pReg->rdh.nCount += 1;
934 pNextRect++;
935 r++;
936 }
937 return;
938 }
939
940 /*!
941 * Handle an overlapping band for the union operation. Picks the
942 * left-most rectangle each time and merges it into the region.
943 *
944 * Results:
945 * None.
946 *
947 * \note Side Effects:
948 * Rectangles are overwritten in pReg->rects and pReg->numRects will
949 * be changed.
950 *
951 */
952 static void FASTCALL REGION_UnionO (ROSRGNDATA *pReg, RECT *r1, RECT *r1End,
953 RECT *r2, RECT *r2End, INT top, INT bottom)
954 {
955 RECT *pNextRect;
956
957 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
958
959 #define MERGERECT(r) \
960 if ((pReg->rdh.nCount != 0) && \
961 ((pNextRect-1)->top == top) && \
962 ((pNextRect-1)->bottom == bottom) && \
963 ((pNextRect-1)->right >= r->left)) \
964 { \
965 if ((pNextRect-1)->right < r->right) \
966 { \
967 (pNextRect-1)->right = r->right; \
968 } \
969 } \
970 else \
971 { \
972 MEMCHECK(pReg, pNextRect, pReg->Buffer); \
973 pNextRect->top = top; \
974 pNextRect->bottom = bottom; \
975 pNextRect->left = r->left; \
976 pNextRect->right = r->right; \
977 pReg->rdh.nCount += 1; \
978 pNextRect += 1; \
979 } \
980 r++;
981
982 while ((r1 != r1End) && (r2 != r2End))
983 {
984 if (r1->left < r2->left)
985 {
986 MERGERECT(r1);
987 }
988 else
989 {
990 MERGERECT(r2);
991 }
992 }
993
994 if (r1 != r1End)
995 {
996 do
997 {
998 MERGERECT(r1);
999 } while (r1 != r1End);
1000 }
1001 else while (r2 != r2End)
1002 {
1003 MERGERECT(r2);
1004 }
1005 return;
1006 }
1007
1008 /***********************************************************************
1009 * REGION_UnionRegion
1010 */
1011 static void FASTCALL REGION_UnionRegion(ROSRGNDATA *newReg, ROSRGNDATA *reg1,
1012 ROSRGNDATA *reg2)
1013 {
1014 /* checks all the simple cases */
1015
1016 /*
1017 * Region 1 and 2 are the same or region 1 is empty
1018 */
1019 if (reg1 == reg2 || 0 == reg1->rdh.nCount ||
1020 reg1->rdh.rcBound.right <= reg1->rdh.rcBound.left ||
1021 reg1->rdh.rcBound.bottom <= reg1->rdh.rcBound.top)
1022 {
1023 if (newReg != reg2)
1024 {
1025 REGION_CopyRegion(newReg, reg2);
1026 }
1027 return;
1028 }
1029
1030 /*
1031 * if nothing to union (region 2 empty)
1032 */
1033 if (0 == reg2->rdh.nCount ||
1034 reg2->rdh.rcBound.right <= reg2->rdh.rcBound.left ||
1035 reg2->rdh.rcBound.bottom <= reg2->rdh.rcBound.top)
1036 {
1037 if (newReg != reg1)
1038 {
1039 REGION_CopyRegion(newReg, reg1);
1040 }
1041 return;
1042 }
1043
1044 /*
1045 * Region 1 completely subsumes region 2
1046 */
1047 if (1 == reg1->rdh.nCount &&
1048 reg1->rdh.rcBound.left <= reg2->rdh.rcBound.left &&
1049 reg1->rdh.rcBound.top <= reg2->rdh.rcBound.top &&
1050 reg2->rdh.rcBound.right <= reg1->rdh.rcBound.right &&
1051 reg2->rdh.rcBound.bottom <= reg1->rdh.rcBound.bottom)
1052 {
1053 if (newReg != reg1)
1054 {
1055 REGION_CopyRegion(newReg, reg1);
1056 }
1057 return;
1058 }
1059
1060 /*
1061 * Region 2 completely subsumes region 1
1062 */
1063 if (1 == reg2->rdh.nCount &&
1064 reg2->rdh.rcBound.left <= reg1->rdh.rcBound.left &&
1065 reg2->rdh.rcBound.top <= reg1->rdh.rcBound.top &&
1066 reg1->rdh.rcBound.right <= reg2->rdh.rcBound.right &&
1067 reg1->rdh.rcBound.bottom <= reg2->rdh.rcBound.bottom)
1068 {
1069 if (newReg != reg2)
1070 {
1071 REGION_CopyRegion(newReg, reg2);
1072 }
1073 return;
1074 }
1075
1076 REGION_RegionOp(newReg, reg1, reg2, REGION_UnionO,
1077 REGION_UnionNonO, REGION_UnionNonO);
1078 newReg->rdh.rcBound.left = min(reg1->rdh.rcBound.left, reg2->rdh.rcBound.left);
1079 newReg->rdh.rcBound.top = min(reg1->rdh.rcBound.top, reg2->rdh.rcBound.top);
1080 newReg->rdh.rcBound.right = max(reg1->rdh.rcBound.right, reg2->rdh.rcBound.right);
1081 newReg->rdh.rcBound.bottom = max(reg1->rdh.rcBound.bottom, reg2->rdh.rcBound.bottom);
1082 }
1083
1084 /***********************************************************************
1085 * Region Subtraction
1086 ***********************************************************************/
1087
1088 /*!
1089 * Deal with non-overlapping band for subtraction. Any parts from
1090 * region 2 we discard. Anything from region 1 we add to the region.
1091 *
1092 * Results:
1093 * None.
1094 *
1095 * \note Side Effects:
1096 * pReg may be affected.
1097 *
1098 */
1099 static void FASTCALL REGION_SubtractNonO1 (ROSRGNDATA *pReg, RECT *r, RECT *rEnd,
1100 INT top, INT bottom)
1101 {
1102 RECT *pNextRect;
1103
1104 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
1105
1106 while (r != rEnd)
1107 {
1108 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1109 pNextRect->left = r->left;
1110 pNextRect->top = top;
1111 pNextRect->right = r->right;
1112 pNextRect->bottom = bottom;
1113 pReg->rdh.nCount += 1;
1114 pNextRect++;
1115 r++;
1116 }
1117 return;
1118 }
1119
1120
1121 /*!
1122 * Overlapping band subtraction. x1 is the left-most point not yet
1123 * checked.
1124 *
1125 * Results:
1126 * None.
1127 *
1128 * \note Side Effects:
1129 * pReg may have rectangles added to it.
1130 *
1131 */
1132 static void FASTCALL REGION_SubtractO (ROSRGNDATA *pReg, RECT *r1, RECT *r1End,
1133 RECT *r2, RECT *r2End, INT top, INT bottom)
1134 {
1135 RECT *pNextRect;
1136 INT left;
1137
1138 left = r1->left;
1139 pNextRect = (PRECT)pReg->Buffer + pReg->rdh.nCount;
1140
1141 while ((r1 != r1End) && (r2 != r2End))
1142 {
1143 if (r2->right <= left)
1144 {
1145 /*
1146 * Subtrahend missed the boat: go to next subtrahend.
1147 */
1148 r2++;
1149 }
1150 else if (r2->left <= left)
1151 {
1152 /*
1153 * Subtrahend preceeds minuend: nuke left edge of minuend.
1154 */
1155 left = r2->right;
1156 if (left >= r1->right)
1157 {
1158 /*
1159 * Minuend completely covered: advance to next minuend and
1160 * reset left fence to edge of new minuend.
1161 */
1162 r1++;
1163 if (r1 != r1End)
1164 left = r1->left;
1165 }
1166 else
1167 {
1168 /*
1169 * Subtrahend now used up since it doesn't extend beyond
1170 * minuend
1171 */
1172 r2++;
1173 }
1174 }
1175 else if (r2->left < r1->right)
1176 {
1177 /*
1178 * Left part of subtrahend covers part of minuend: add uncovered
1179 * part of minuend to region and skip to next subtrahend.
1180 */
1181 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1182 pNextRect->left = left;
1183 pNextRect->top = top;
1184 pNextRect->right = r2->left;
1185 pNextRect->bottom = bottom;
1186 pReg->rdh.nCount += 1;
1187 pNextRect++;
1188 left = r2->right;
1189 if (left >= r1->right)
1190 {
1191 /*
1192 * Minuend used up: advance to new...
1193 */
1194 r1++;
1195 if (r1 != r1End)
1196 left = r1->left;
1197 }
1198 else
1199 {
1200 /*
1201 * Subtrahend used up
1202 */
1203 r2++;
1204 }
1205 }
1206 else
1207 {
1208 /*
1209 * Minuend used up: add any remaining piece before advancing.
1210 */
1211 if (r1->right > left)
1212 {
1213 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1214 pNextRect->left = left;
1215 pNextRect->top = top;
1216 pNextRect->right = r1->right;
1217 pNextRect->bottom = bottom;
1218 pReg->rdh.nCount += 1;
1219 pNextRect++;
1220 }
1221 r1++;
1222 left = r1->left;
1223 }
1224 }
1225
1226 /*
1227 * Add remaining minuend rectangles to region.
1228 */
1229 while (r1 != r1End)
1230 {
1231 MEMCHECK(pReg, pNextRect, pReg->Buffer);
1232 pNextRect->left = left;
1233 pNextRect->top = top;
1234 pNextRect->right = r1->right;
1235 pNextRect->bottom = bottom;
1236 pReg->rdh.nCount += 1;
1237 pNextRect++;
1238 r1++;
1239 if (r1 != r1End)
1240 {
1241 left = r1->left;
1242 }
1243 }
1244 return;
1245 }
1246
1247 /*!
1248 * Subtract regS from regM and leave the result in regD.
1249 * S stands for subtrahend, M for minuend and D for difference.
1250 *
1251 * Results:
1252 * TRUE.
1253 *
1254 * \note Side Effects:
1255 * regD is overwritten.
1256 *
1257 */
1258 static void FASTCALL REGION_SubtractRegion(ROSRGNDATA *regD, ROSRGNDATA *regM,
1259 ROSRGNDATA *regS )
1260 {
1261 /* check for trivial reject */
1262 if ( (!(regM->rdh.nCount)) || (!(regS->rdh.nCount)) ||
1263 (!EXTENTCHECK(&regM->rdh.rcBound, &regS->rdh.rcBound)) )
1264 {
1265 REGION_CopyRegion(regD, regM);
1266 return;
1267 }
1268
1269 REGION_RegionOp (regD, regM, regS, REGION_SubtractO,
1270 REGION_SubtractNonO1, NULL);
1271
1272 /*
1273 * Can't alter newReg's extents before we call miRegionOp because
1274 * it might be one of the source regions and miRegionOp depends
1275 * on the extents of those regions being the unaltered. Besides, this
1276 * way there's no checking against rectangles that will be nuked
1277 * due to coalescing, so we have to examine fewer rectangles.
1278 */
1279 REGION_SetExtents (regD);
1280 }
1281
1282 /***********************************************************************
1283 * REGION_XorRegion
1284 */
1285 static void FASTCALL REGION_XorRegion(ROSRGNDATA *dr, ROSRGNDATA *sra,
1286 ROSRGNDATA *srb)
1287 {
1288 HRGN htra, htrb;
1289 ROSRGNDATA *tra, *trb;
1290
1291 if ((! (htra = RGNDATA_AllocRgn(sra->rdh.nCount + 1))) ||
1292 (! (htrb = RGNDATA_AllocRgn(srb->rdh.nCount + 1))))
1293 return;
1294 tra = RGNDATA_LockRgn( htra );
1295 if( !tra ){
1296 W32kDeleteObject( htra );
1297 W32kDeleteObject( htrb );
1298 return;
1299 }
1300
1301 trb = RGNDATA_LockRgn( htrb );
1302 if( !trb ){
1303 RGNDATA_UnlockRgn( htra );
1304 W32kDeleteObject( htra );
1305 W32kDeleteObject( htrb );
1306 return;
1307 }
1308
1309 REGION_SubtractRegion(tra,sra,srb);
1310 REGION_SubtractRegion(trb,srb,sra);
1311 REGION_UnionRegion(dr,tra,trb);
1312 RGNDATA_UnlockRgn( htra );
1313 RGNDATA_UnlockRgn( htrb );
1314
1315 W32kDeleteObject( htra );
1316 W32kDeleteObject( htrb );
1317 return;
1318 }
1319
1320
1321 /*!
1322 * Adds a rectangle to a REGION
1323 */
1324 static void FASTCALL REGION_UnionRectWithRegion(const RECT *rect, ROSRGNDATA *rgn)
1325 {
1326 ROSRGNDATA region;
1327
1328 region.Buffer = (char*)(&(region.rdh.rcBound));
1329 region.rdh.nCount = 1;
1330 region.rdh.nRgnSize = sizeof( RECT );
1331 region.rdh.rcBound = *rect;
1332 REGION_UnionRegion(rgn, rgn, &region);
1333 }
1334
1335
1336 BOOL STDCALL REGION_LPTODP(HDC hdc, HRGN hDest, HRGN hSrc)
1337 {
1338 RECT *pCurRect, *pEndRect;
1339 PROSRGNDATA srcObj = NULL;
1340 PROSRGNDATA destObj = NULL;
1341
1342 DC * dc = DC_HandleToPtr(hdc);
1343 RECT tmpRect;
1344 BOOL ret = FALSE;
1345
1346 if(!dc)
1347 return ret;
1348
1349 if(dc->w.MapMode == MM_TEXT) // Requires only a translation
1350 {
1351 if(W32kCombineRgn(hDest, hSrc, 0, RGN_COPY) == ERROR)
1352 goto done;
1353
1354 W32kOffsetRgn(hDest, dc->vportOrgX - dc->wndOrgX, dc->vportOrgY - dc->wndOrgY);
1355 ret = TRUE;
1356 goto done;
1357 }
1358
1359 if(!( srcObj = (PROSRGNDATA) RGNDATA_LockRgn( hSrc ) ))
1360 goto done;
1361 if(!( destObj = (PROSRGNDATA) RGNDATA_LockRgn( hDest ) ))
1362 {
1363 RGNDATA_UnlockRgn( hSrc );
1364 goto done;
1365 }
1366 EMPTY_REGION(destObj);
1367
1368 pEndRect = (PRECT)srcObj->Buffer + srcObj->rdh.nCount;
1369 for(pCurRect = (PRECT)srcObj->Buffer; pCurRect < pEndRect; pCurRect++)
1370 {
1371 tmpRect = *pCurRect;
1372 tmpRect.left = XLPTODP(dc, tmpRect.left);
1373 tmpRect.top = YLPTODP(dc, tmpRect.top);
1374 tmpRect.right = XLPTODP(dc, tmpRect.right);
1375 tmpRect.bottom = YLPTODP(dc, tmpRect.bottom);
1376
1377 if(tmpRect.left > tmpRect.right)
1378 { INT tmp = tmpRect.left; tmpRect.left = tmpRect.right; tmpRect.right = tmp; }
1379 if(tmpRect.top > tmpRect.bottom)
1380 { INT tmp = tmpRect.top; tmpRect.top = tmpRect.bottom; tmpRect.bottom = tmp; }
1381
1382 REGION_UnionRectWithRegion(&tmpRect, destObj);
1383 }
1384 ret = TRUE;
1385
1386 RGNDATA_UnlockRgn( hSrc );
1387 RGNDATA_UnlockRgn( hDest );
1388
1389 done:
1390 DC_ReleasePtr( hdc );
1391 return ret;
1392 }
1393
1394 HRGN FASTCALL RGNDATA_AllocRgn(INT n)
1395 {
1396 HRGN hReg;
1397 PROSRGNDATA pReg;
1398 BOOL bRet;
1399
1400 if((hReg = (HRGN)GDIOBJ_AllocObj(sizeof(ROSRGNDATA), GO_REGION_MAGIC))){
1401 if( (pReg = GDIOBJ_LockObj( hReg, GO_REGION_MAGIC )) ){
1402
1403 if ((pReg->Buffer = ExAllocatePool(PagedPool, n * sizeof(RECT)))){
1404 EMPTY_REGION(pReg);
1405 pReg->rdh.dwSize = sizeof(RGNDATAHEADER);
1406 pReg->rdh.nCount = n;
1407 pReg->rdh.nRgnSize = n*sizeof(RECT);
1408
1409 bRet = GDIOBJ_UnlockObj( hReg, GO_REGION_MAGIC );
1410 ASSERT(bRet);
1411
1412 return hReg;
1413 }
1414
1415 }
1416 else
1417 GDIOBJ_FreeObj( hReg, GO_REGION_MAGIC, GDIOBJFLAG_DEFAULT );
1418 }
1419 return NULL;
1420 }
1421
1422 BOOL FASTCALL RGNDATA_InternalDelete( PROSRGNDATA pRgn )
1423 {
1424 ASSERT(pRgn);
1425 if(pRgn->Buffer)
1426 ExFreePool(pRgn->Buffer);
1427 return TRUE;
1428 }
1429
1430 // W32k Exported Functions
1431 INT
1432 STDCALL
1433 W32kCombineRgn(HRGN hDest,
1434 HRGN hSrc1,
1435 HRGN hSrc2,
1436 INT CombineMode)
1437 {
1438 INT result = ERROR;
1439 GDIMULTILOCK Lock[3] = {{hDest, 0, GO_REGION_MAGIC}, {hSrc1, 0, GO_REGION_MAGIC}, {hSrc2, 0, GO_REGION_MAGIC}};
1440 PROSRGNDATA destRgn, src1Rgn, src2Rgn;
1441
1442 GDIOBJ_LockMultipleObj(Lock, 3);
1443
1444 destRgn = (PROSRGNDATA) Lock[0].pObj;
1445 src1Rgn = (PROSRGNDATA) Lock[1].pObj;
1446 src2Rgn = (PROSRGNDATA) Lock[2].pObj;
1447
1448 if( destRgn ){
1449 if( src1Rgn ){
1450 if (CombineMode == RGN_COPY)
1451 {
1452 if( !REGION_CopyRegion(destRgn, src1Rgn) )
1453 return ERROR;
1454 result = destRgn->rdh.iType;
1455 }
1456 else
1457 {
1458 if( src2Rgn ){
1459 switch (CombineMode)
1460 {
1461 case RGN_AND:
1462 REGION_IntersectRegion(destRgn, src1Rgn, src2Rgn);
1463 break;
1464 case RGN_OR:
1465 REGION_UnionRegion(destRgn, src1Rgn, src2Rgn);
1466 break;
1467 case RGN_XOR:
1468 REGION_XorRegion(destRgn, src1Rgn, src2Rgn);
1469 break;
1470 case RGN_DIFF:
1471 REGION_SubtractRegion(destRgn, src1Rgn, src2Rgn);
1472 break;
1473 }
1474 result = destRgn->rdh.iType;
1475 }
1476 }
1477 }
1478 }
1479 else{
1480 DPRINT("W32kCombineRgn: hDest unavailable\n");
1481 result = ERROR;
1482 }
1483 GDIOBJ_UnlockMultipleObj(Lock, 3);
1484 return result;
1485 }
1486
1487 HRGN
1488 STDCALL
1489 W32kCreateEllipticRgn(INT LeftRect,
1490 INT TopRect,
1491 INT RightRect,
1492 INT BottomRect)
1493 {
1494 UNIMPLEMENTED;
1495 }
1496
1497 HRGN
1498 STDCALL
1499 W32kCreateEllipticRgnIndirect(CONST PRECT rc)
1500 {
1501 UNIMPLEMENTED;
1502 }
1503
1504 HRGN
1505 STDCALL
1506 W32kCreatePolygonRgn(CONST PPOINT pt,
1507 INT Count,
1508 INT PolyFillMode)
1509 {
1510 UNIMPLEMENTED;
1511 }
1512
1513 HRGN
1514 STDCALL
1515 W32kCreatePolyPolygonRgn(CONST PPOINT pt,
1516 CONST PINT PolyCounts,
1517 INT Count,
1518 INT PolyFillMode)
1519 {
1520 UNIMPLEMENTED;
1521 }
1522
1523 HRGN
1524 STDCALL
1525 W32kCreateRectRgn(INT LeftRect,
1526 INT TopRect,
1527 INT RightRect,
1528 INT BottomRect)
1529 {
1530 HRGN hRgn;
1531 PROSRGNDATA pRgnData;
1532 PRECT pRect;
1533
1534 // Allocate region data structure with space for 1 RECT
1535 if( ( hRgn = RGNDATA_AllocRgn(1) ) ){
1536 if( ( pRgnData = RGNDATA_LockRgn( hRgn ) ) ){
1537 pRect = (PRECT)pRgnData->Buffer;
1538 ASSERT(pRect);
1539
1540 // Fill in the region data header
1541 pRgnData->rdh.iType = SIMPLEREGION;
1542 W32kSetRect(&(pRgnData->rdh.rcBound), LeftRect, TopRect, RightRect, BottomRect);
1543
1544 // use W32kCopyRect when implemented
1545 W32kSetRect(pRect, LeftRect, TopRect, RightRect, BottomRect);
1546 RGNDATA_UnlockRgn( hRgn );
1547
1548 return hRgn;
1549 }
1550 W32kDeleteObject( hRgn );
1551 }
1552 DPRINT("W32kCreateRectRgn: can't allocate region\n");
1553 return NULL;
1554 }
1555
1556 HRGN STDCALL
1557 W32kCreateRectRgnIndirect(CONST PRECT rc)
1558 {
1559 RECT SafeRc;
1560 NTSTATUS Status;
1561
1562 Status = MmCopyFromCaller(&SafeRc, rc, sizeof(RECT));
1563 if (!NT_SUCCESS(Status))
1564 {
1565 return(NULL);
1566 }
1567 return(UnsafeW32kCreateRectRgnIndirect(&SafeRc));
1568 }
1569
1570 HRGN STDCALL
1571 UnsafeW32kCreateRectRgnIndirect(CONST PRECT rc)
1572 {
1573 return(W32kCreateRectRgn(rc->left, rc->top, rc->right, rc->bottom));
1574 }
1575
1576 HRGN
1577 STDCALL
1578 W32kCreateRoundRectRgn(INT LeftRect,
1579 INT TopRect,
1580 INT RightRect,
1581 INT BottomRect,
1582 INT WidthEllipse,
1583 INT HeightEllipse)
1584 {
1585 UNIMPLEMENTED;
1586 }
1587
1588 BOOL
1589 STDCALL
1590 W32kEqualRgn(HRGN hSrcRgn1,
1591 HRGN hSrcRgn2)
1592 {
1593 PROSRGNDATA rgn1, rgn2;
1594 PRECT tRect1, tRect2;
1595 int i;
1596 BOOL bRet = FALSE;
1597
1598 if( !(rgn1 = RGNDATA_LockRgn(hSrcRgn1)))
1599 return ERROR;
1600
1601 if( !(rgn2 = RGNDATA_LockRgn(hSrcRgn2))){
1602 RGNDATA_UnlockRgn( hSrcRgn1 );
1603 return ERROR;
1604 }
1605
1606 if(rgn1->rdh.nCount != rgn2->rdh.nCount ||
1607 rgn1->rdh.nCount == 0 ||
1608 rgn1->rdh.rcBound.left != rgn2->rdh.rcBound.left ||
1609 rgn1->rdh.rcBound.right != rgn2->rdh.rcBound.right ||
1610 rgn1->rdh.rcBound.top != rgn2->rdh.rcBound.top ||
1611 rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom)
1612 goto exit;
1613
1614 tRect1 = (PRECT)rgn1->Buffer;
1615 tRect2 = (PRECT)rgn2->Buffer;
1616
1617 if( !tRect1 || !tRect2 )
1618 goto exit;
1619
1620 for(i=0; i < rgn1->rdh.nCount; i++)
1621 {
1622 if(tRect1[i].left != tRect2[i].left ||
1623 tRect1[i].right != tRect2[i].right ||
1624 tRect1[i].top != tRect2[i].top ||
1625 tRect1[i].bottom != tRect2[i].bottom)
1626 goto exit;;
1627 }
1628 bRet = TRUE;
1629
1630 exit:
1631 RGNDATA_UnlockRgn( hSrcRgn1 );
1632 RGNDATA_UnlockRgn( hSrcRgn2 );
1633 return bRet;
1634 }
1635
1636 HRGN
1637 STDCALL
1638 W32kExtCreateRegion(CONST PXFORM Xform,
1639 DWORD Count,
1640 CONST PROSRGNDATA RgnData)
1641 {
1642 HRGN hRgn;
1643
1644 // FIXME: Apply Xform transformation to the regional data
1645 if(Xform != NULL) {
1646
1647 }
1648
1649 return hRgn;
1650 }
1651
1652 BOOL
1653 STDCALL
1654 W32kFillRgn(HDC hDC, HRGN hRgn, HBRUSH hBrush)
1655 {
1656 HBRUSH oldhBrush;
1657 PROSRGNDATA rgn;
1658 PRECTL r;
1659
1660 if (NULL == (rgn = RGNDATA_LockRgn(hRgn)))
1661 {
1662 return FALSE;
1663 }
1664
1665 if (NULL == (oldhBrush = W32kSelectObject(hDC, hBrush)))
1666 {
1667 RGNDATA_UnlockRgn(hRgn);
1668 return FALSE;
1669 }
1670
1671 for (r = (PRECT) rgn->Buffer; r < ((PRECT) rgn->Buffer) + rgn->rdh.nCount; r++)
1672 {
1673 W32kPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY);
1674 }
1675
1676 W32kSelectObject(hDC, oldhBrush);
1677 RGNDATA_UnlockRgn( hRgn );
1678
1679 return TRUE;
1680 }
1681
1682 BOOL
1683 STDCALL
1684 W32kFrameRgn(HDC hDC,
1685 HRGN hRgn,
1686 HBRUSH hBrush,
1687 INT Width,
1688 INT Height)
1689 {
1690 UNIMPLEMENTED;
1691 }
1692
1693 INT STDCALL
1694 UnsafeW32kGetRgnBox(HRGN hRgn,
1695 LPRECT pRect)
1696 {
1697 PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1698 DWORD ret;
1699
1700 if (rgn)
1701 {
1702 *pRect = rgn->rdh.rcBound;
1703 ret = rgn->rdh.iType;
1704 RGNDATA_UnlockRgn( hRgn );
1705
1706 return ret;
1707 }
1708 return 0; //if invalid region return zero
1709 }
1710
1711
1712 INT STDCALL
1713 W32kGetRgnBox(HRGN hRgn,
1714 LPRECT pRect)
1715 {
1716 PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1717 DWORD ret;
1718
1719 if (rgn)
1720 {
1721 RECT SafeRect;
1722 SafeRect.left = rgn->rdh.rcBound.left;
1723 SafeRect.top = rgn->rdh.rcBound.top;
1724 SafeRect.right = rgn->rdh.rcBound.right;
1725 SafeRect.bottom = rgn->rdh.rcBound.bottom;
1726 ret = rgn->rdh.iType;
1727 RGNDATA_UnlockRgn( hRgn );
1728
1729 if(!NT_SUCCESS(MmCopyToCaller(pRect, &SafeRect, sizeof(RECT))))
1730 return 0;
1731
1732 return ret;
1733 }
1734 return 0; //if invalid region return zero
1735 }
1736
1737 BOOL
1738 STDCALL
1739 W32kInvertRgn(HDC hDC,
1740 HRGN hRgn)
1741 {
1742 UNIMPLEMENTED;
1743 }
1744
1745 INT
1746 STDCALL
1747 W32kOffsetRgn(HRGN hRgn,
1748 INT XOffset,
1749 INT YOffset)
1750 {
1751 PROSRGNDATA rgn = RGNDATA_LockRgn(hRgn);
1752 INT ret;
1753
1754 DPRINT("W32kOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
1755
1756 if( !rgn ){
1757 DPRINT("W32kOffsetRgn: hRgn error\n");
1758 return ERROR;
1759 }
1760
1761 if(XOffset || YOffset) {
1762 int nbox = rgn->rdh.nCount;
1763 PRECT pbox = (PRECT)rgn->Buffer;
1764
1765 if(nbox && pbox) {
1766 while(nbox--) {
1767 pbox->left += XOffset;
1768 pbox->right += XOffset;
1769 pbox->top += YOffset;
1770 pbox->bottom += YOffset;
1771 pbox++;
1772 }
1773 rgn->rdh.rcBound.left += XOffset;
1774 rgn->rdh.rcBound.right += XOffset;
1775 rgn->rdh.rcBound.top += YOffset;
1776 rgn->rdh.rcBound.bottom += YOffset;
1777 }
1778 }
1779 ret = rgn->rdh.iType;
1780 RGNDATA_UnlockRgn( hRgn );
1781 return ret;
1782 }
1783
1784 BOOL
1785 STDCALL
1786 W32kPaintRgn(HDC hDC,
1787 HRGN hRgn)
1788 {
1789 //RECT box;
1790 HRGN tmpVisRgn; //, prevVisRgn;
1791 DC *dc = DC_HandleToPtr(hDC);
1792 PROSRGNDATA visrgn;
1793 CLIPOBJ* ClipRegion;
1794 BOOL bRet = FALSE;
1795 PBRUSHOBJ pBrush;
1796 POINTL BrushOrigin;
1797 SURFOBJ *SurfObj;
1798
1799 if( !dc )
1800 return FALSE;
1801
1802 if(!(tmpVisRgn = W32kCreateRectRgn(0, 0, 0, 0))){
1803 DC_ReleasePtr( hDC );
1804 return FALSE;
1805 }
1806
1807 /* ei enable later
1808 // Transform region into device co-ords
1809 if(!REGION_LPTODP(hDC, tmpVisRgn, hRgn) || W32kOffsetRgn(tmpVisRgn, dc->w.DCOrgX, dc->w.DCOrgY) == ERROR) {
1810 W32kDeleteObject( tmpVisRgn );
1811 DC_ReleasePtr( hDC );
1812 return FALSE;
1813 }
1814 */
1815 /* enable when clipping is implemented
1816 W32kCombineRgn(tmpVisRgn, tmpVisRgn, dc->w.hGCClipRgn, RGN_AND);
1817 */
1818
1819 //visrgn = RGNDATA_LockRgn(tmpVisRgn);
1820 visrgn = RGNDATA_LockRgn(hRgn);
1821
1822 ClipRegion = IntEngCreateClipRegion( visrgn->rdh.nCount, visrgn->Buffer, visrgn->rdh.rcBound );
1823 ASSERT( ClipRegion );
1824 pBrush = BRUSHOBJ_LockBrush(dc->w.hBrush);
1825 ASSERT(pBrush);
1826 BrushOrigin.x = dc->w.brushOrgX;
1827 BrushOrigin.y = dc->w.brushOrgY;
1828 SurfObj = (SURFOBJ*)AccessUserObject((ULONG)dc->Surface);
1829
1830 bRet = IntEngPaint(SurfObj,
1831 ClipRegion,
1832 pBrush,
1833 &BrushOrigin,
1834 0xFFFF);//FIXME:don't know what to put here
1835
1836 RGNDATA_UnlockRgn( tmpVisRgn );
1837
1838 // Fill the region
1839 DC_ReleasePtr( hDC );
1840 return TRUE;
1841 }
1842
1843 BOOL
1844 STDCALL
1845 W32kPtInRegion(HRGN hRgn,
1846 INT X,
1847 INT Y)
1848 {
1849 PROSRGNDATA rgn;
1850 int i;
1851
1852 if( (rgn = RGNDATA_LockRgn(hRgn) ) )
1853 return FALSE;
1854
1855 if(rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y)){
1856 for(i = 0; i < rgn->rdh.nCount; i++) {
1857 if(INRECT(*(PRECT)&rgn->Buffer[i], X, Y)){
1858 RGNDATA_UnlockRgn(hRgn);
1859 return TRUE;
1860 }
1861 }
1862 }
1863 RGNDATA_UnlockRgn(hRgn);
1864 return FALSE;
1865 }
1866
1867 BOOL
1868 STDCALL
1869 W32kRectInRegion(HRGN hRgn,
1870 CONST LPRECT unsaferc)
1871 {
1872 PROSRGNDATA rgn;
1873 PRECT pCurRect, pRectEnd;
1874 PRECT rc;
1875 BOOL bRet = FALSE;
1876
1877 if( !NT_SUCCESS( MmCopyFromCaller( rc, unsaferc, sizeof( RECT ) ) ) ){
1878 DPRINT("W32kRectInRegion: bogus rc\n");
1879 return ERROR;
1880 }
1881
1882 if( !( rgn = RGNDATA_LockRgn(hRgn) ) )
1883 return ERROR;
1884
1885 // this is (just) a useful optimization
1886 if((rgn->rdh.nCount > 0) && EXTENTCHECK(&rgn->rdh.rcBound, rc))
1887 {
1888 for (pCurRect = (PRECT)rgn->Buffer, pRectEnd = pCurRect + rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
1889 {
1890 if (pCurRect->bottom <= rc->top) continue; // not far enough down yet
1891 if (pCurRect->top >= rc->bottom) break; // too far down
1892 if (pCurRect->right <= rc->left) continue; // not far enough over yet
1893 if (pCurRect->left >= rc->right) continue;
1894 bRet = TRUE;
1895 break;
1896 }
1897 }
1898 RGNDATA_UnlockRgn(hRgn);
1899 return bRet;
1900 }
1901
1902 BOOL
1903 STDCALL
1904 W32kSetRectRgn(HRGN hRgn,
1905 INT LeftRect,
1906 INT TopRect,
1907 INT RightRect,
1908 INT BottomRect)
1909 {
1910 PROSRGNDATA rgn;
1911 PRECT firstRect;
1912
1913
1914
1915 if( !( rgn = RGNDATA_LockRgn(hRgn) ) )
1916 return 0; //per documentation
1917
1918 if (LeftRect > RightRect) { INT tmp = LeftRect; LeftRect = RightRect; RightRect = tmp; }
1919 if (TopRect > BottomRect) { INT tmp = TopRect; TopRect = BottomRect; BottomRect = tmp; }
1920
1921 if((LeftRect != RightRect) && (TopRect != BottomRect))
1922 {
1923 firstRect = (PRECT)rgn->Buffer;
1924 ASSERT( firstRect );
1925 firstRect->left = rgn->rdh.rcBound.left = LeftRect;
1926 firstRect->top = rgn->rdh.rcBound.top = TopRect;
1927 firstRect->right = rgn->rdh.rcBound.right = RightRect;
1928 firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
1929 rgn->rdh.nCount = 1;
1930 rgn->rdh.iType = SIMPLEREGION;
1931 } else
1932 EMPTY_REGION(rgn);
1933
1934 RGNDATA_UnlockRgn( hRgn );
1935 return TRUE;
1936 }
1937
1938 HRGN FASTCALL
1939 UnsafeW32kUnionRectWithRgn(HRGN hDest, CONST PRECT Rect)
1940 {
1941 PROSRGNDATA pRgn;
1942
1943 pRgn = RGNDATA_LockRgn(hDest);
1944 if (NULL == pRgn)
1945 {
1946 SetLastWin32Error(ERROR_INVALID_HANDLE);
1947 return NULL;
1948 }
1949
1950 REGION_UnionRectWithRegion(Rect, pRgn);
1951 RGNDATA_UnlockRgn(hDest);
1952
1953 return hDest;
1954 }
1955
1956 HRGN STDCALL
1957 W32kUnionRectWithRgn(HRGN hDest, CONST PRECT UnsafeRect)
1958 {
1959 RECT SafeRect;
1960
1961 if (! NT_SUCCESS(MmCopyFromCaller(&SafeRect, UnsafeRect, sizeof(RECT))))
1962 {
1963 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1964 return NULL;
1965 }
1966
1967 return UnsafeW32kUnionRectWithRgn(hDest, &SafeRect);
1968 }
1969
1970 /*!
1971 * MSDN: GetRegionData, Return Values:
1972 *
1973 * "If the function succeeds and dwCount specifies an adequate number of bytes,
1974 * the return value is always dwCount. If dwCount is too small or the function
1975 * fails, the return value is 0. If lpRgnData is NULL, the return value is the
1976 * required number of bytes.
1977 *
1978 * If the function fails, the return value is zero."
1979 */
1980 DWORD STDCALL W32kGetRegionData(HRGN hrgn, DWORD count, LPRGNDATA rgndata)
1981 {
1982 DWORD size;
1983 PROSRGNDATA obj = RGNDATA_LockRgn( hrgn );
1984
1985 if(!obj)
1986 return 0;
1987
1988 size = obj->rdh.nCount * sizeof(RECT);
1989 if(count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
1990 {
1991 RGNDATA_UnlockRgn( hrgn );
1992 if (rgndata) /* buffer is too small, signal it by return 0 */
1993 return 0;
1994 else /* user requested buffer size with rgndata NULL */
1995 return size + sizeof(RGNDATAHEADER);
1996 }
1997
1998 //first we copy the header then we copy buffer
1999 if( !NT_SUCCESS( MmCopyToCaller( rgndata, obj, sizeof( RGNDATAHEADER )))){
2000 RGNDATA_UnlockRgn( hrgn );
2001 return 0;
2002 }
2003 if( !NT_SUCCESS( MmCopyToCaller( (char*)rgndata+sizeof( RGNDATAHEADER ), obj->Buffer, size ))){
2004 RGNDATA_UnlockRgn( hrgn );
2005 return 0;
2006 }
2007
2008 RGNDATA_UnlockRgn( hrgn );
2009 return size + sizeof(RGNDATAHEADER);
2010 }
2011 /* EOF */