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