This patch introduces no functional change, but makes some ugly code a little prettier.
--- server/region.c | 1036 ++++++++++++++++------------------------------- 1 file changed, 339 insertions(+), 697 deletions(-)
diff --git a/server/region.c b/server/region.c index 9f377ee05d3..ca5aba8cd63 100644 --- a/server/region.c +++ b/server/region.c @@ -72,709 +72,351 @@ SOFTWARE.
************************************************************************/
-#include <stdarg.h> -#include <stdlib.h> -#include <string.h> -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "winternl.h" -#include "request.h" -#include "user.h"
-struct region -{ - int size; - int num_rects; - rectangle_t *rects; - rectangle_t extents; -}; +#include <stdarg.h> + #include <stdlib.h> + #include <string.h> + #include "ntstatus.h" + #define WIN32_NO_STATUS + #include "winternl.h" + #include "request.h" + #include"user.h" + struct region + {int size;int + num_rects ; + rectangle_t + *rects; rectangle_t extents;}; + # define RGN_DEFAULT_RECTS 2 + # define EXTENTCHECK( \ + r1 ,r2)((r1 )->right >\ + (r2)->left &&(\ + r1) ->left<(\ + r2)->right\ + &&(r1 )->bottom > (r2)\ + ->top&&(r1 )->top<(r2) ->bottom) + typedef int(* overlap_func_t)( struct region + * reg, const rectangle_t*r1,const rectangle_t* + r1End, const rectangle_t*r2,const rectangle_t* + r2End ,int top ,int bottom ); typedef int(* + non_overlap_func_t )(struct region* reg ,const + rectangle_t* r,const rectangle_t* rEnd,int top + ,int bottom );static const rectangle_t + empty_rect; /*all-zero rectangle for empty + regions */ /*add a rectangle to a region + */ static inline rectangle_t *add_rect ( + struct region * reg ){ if (reg-> num_rects >= + reg ->size ){ rectangle_t*new_rect =realloc(reg + -> rects , 2* sizeof(rectangle_t )*reg->size); + if(!new_rect) { set_error ( STATUS_NO_MEMORY + );return NULL;}reg->rects=new_rect;reg->size *= 2; + }return reg->rects +reg->num_rects++;}/* + make sure all the rectangles + are valid and that + the region is + properly y-x- + banded */static + inline int validate_rectangles (const + rectangle_t *rects,unsigned int nb_rects){ + const rectangle_t*ptr,*end; for(ptr + =rects ,end=rects+nb_rects; ptr<end + ;ptr++ ){ if(is_rect_empty( ptr )) + return 0 ;/*empty rectangle*/ if(ptr== + end-1)break; if(ptr[0].top == ptr[1 ].top)/*same + band*/{if(ptr[0]. bottom!=ptr[1].bottom) return 0; /* not + same y extent*/if ( ptr[0].right >= ptr[1].left)return 0;/*not + properly x ordered*/}else/*new band*/{if(ptr[0].bottom> + ptr[1].top)return 0;/*not properly y ordered + */}}return 1;}/*attempt to merge + the rects in the current band with those in + the previous one. Used only by region_op. */ static int + coalesce_region(struct region*pReg,int prevStart,int curStart){ + int curNumRects; rectangle_t*pRegEnd= & pReg->rects[pReg + ->num_rects]; rectangle_t*pPrevRect= &pReg->rects + [prevStart ];rectangle_t*pCurRect =&pReg-> + rects[ curStart];int prevNumRects= curStart- +prevStart ;int bandtop=pCurRect-> top;for( +curNumRects =0;(pCurRect!=pRegEnd) &&(pCurRect + ->top==bandtop );curNumRects++){pCurRect ++;}if(pCurRect + !=pRegEnd){pRegEnd --;while(pRegEnd[-1].top == pRegEnd -> top) + pRegEnd--;curStart= pRegEnd-pReg->rects; pRegEnd=pReg->rects+ + pReg->num_rects;}if((curNumRects==prevNumRects)&&(curNumRects + !=0)){pCurRect-=curNumRects;if (pPrevRect->bottom == + pCurRect->top){ do{ if((pPrevRect->left != + pCurRect->left) ||(pPrevRect-> + right != pCurRect->right))return curStart; + pPrevRect++; pCurRect++; prevNumRects -= 1; } while( + prevNumRects != 0);pReg->num_rects -= curNumRects;pCurRect -= + curNumRects;pPrevRect -= curNumRects;do{ pPrevRect->bottom= + pCurRect->bottom; pPrevRect++;pCurRect ++; curNumRects-= + 1;} while ( curNumRects != 0);if ( pCurRect == + pRegEnd) curStart= prevStart; else do{* +pPrevRect ++ = *pCurRect++;} while ( +pCurRect !=pRegEnd);}} return curStart + ;}/*apply an operation to two regions */ + /*check the GDI version of the code for + explanations */ static int region_op (struct region* + newReg,const struct region*reg1,const struct region *reg2, + overlap_func_t overlap_func,non_overlap_func_t + non_overlap1_func,non_overlap_func_t + non_overlap2_func){int ybot,ytop,top,bot,prevBand + ,curBand; const rectangle_t * r1BandEnd, *r2BandEnd; const + rectangle_t*r1= reg1->rects; const rectangle_t*r2= + reg2->rects ;const rectangle_t *r1End =r1+ + reg1-> num_rects ;const rectangle_t + *r2End =r2+reg2->num_rects; rectangle_t* +new_rects ,*old_rects=newReg ->rects; + int new_size ,ret=0;new_size=max( reg1->num_rects + ,reg2->num_rects )*2;if(!(new_rects= mem_alloc(new_size + *sizeof(*newReg ->rects)))) return 0;newReg->size= + new_size; newReg ->rects=new_rects; newReg->num_rects + =0;if(reg1->extents.top< reg2->extents.top)ybot=reg1-> + extents.top;else ybot = reg2->extents.top; + prevBand=0;do{curBand=newReg->num_rects; r1BandEnd=r1; + while((r1BandEnd!=r1End) && (r1BandEnd->top==r1->top)) + r1BandEnd++;r2BandEnd=r2;while((r2BandEnd != r2End)&&( + r2BandEnd->top == r2->top))r2BandEnd++;if(r1->top<r2-> + top){top=max(r1->top,ybot);bot=min(r1->bottom,r2->top) + ;if(top!=bot&&non_overlap1_func){if(!non_overlap1_func + (newReg,r1,r1BandEnd,top,bot))goto done;}ytop=r2->top; + }else if(r2->top < r1->top){top=max(r2->top,ybot);bot= + min(r2->bottom,r1->top);if(top!=bot&&non_overlap2_func + ){if (!non_overlap2_func(newReg,r2,r2BandEnd,top,bot)) goto done;} + ytop=r1->top;}else{ytop=r1->top;}if (newReg->num_rects != curBand) + prevBand = coalesce_region(newReg,prevBand,curBand); ybot=min(r1-> + bottom,r2->bottom); curBand = newReg->num_rects;if(ybot>ytop){if(! + overlap_func(newReg,r1,r1BandEnd,r2,r2BandEnd,ytop,ybot))goto done + ;}if(newReg->num_rects!=curBand)prevBand = coalesce_region(newReg, + prevBand,curBand);if(r1->bottom==ybot)r1=r1BandEnd;if(r2->bottom== +ybot)r2=r2BandEnd;}while((r1!=r1End)&&(r2!=r2End));curBand=newReg->num_rects;if( +r1 != r1End){if (non_overlap1_func){do{r1BandEnd=r1;while((r1BandEnd < r1End)&&( +r1BandEnd->top==r1->top))r1BandEnd++;if (!non_overlap1_func(newReg,r1,r1BandEnd, +max(r1->top,ybot),r1->bottom))goto done;r1=r1BandEnd;}while(r1!=r1End);}}else if +((r2!=r2End) && non_overlap2_func){do{r2BandEnd=r2;while ((r2BandEnd < r2End)&&( +r2BandEnd->top==r2->top))r2BandEnd++;if (!non_overlap2_func(newReg,r2,r2BandEnd, +max(r2->top, ybot ),r2->bottom +))goto done; r2=r2BandEnd;} while (r2!=r2End); +}if(newReg-> num_rects!=curBand)coalesce_region ( newReg , +prevBand , curBand);if((newReg->num_rects<(newReg->size/ 2))&&(newReg +->size >2)){ new_size=max(newReg->num_rects,RGN_DEFAULT_RECTS); if(new_rects += realloc( newReg->rects, sizeof (* newReg ->rects)* new_size )){ +newReg->rects=new_rects;newReg ->size=new_size;}}ret=1; done: +free(old_rects);return ret; }/* recalculate the extents +of a region */static void set_region_extents(struct +region*region){rectangle_t *pRect,*pRectEnd;if(region +->num_rects==0){region-> extents.left= 0;region-> +extents.top = 0;region-> extents.right=0;region-> +extents.bottom=0;return; }pRect = region-> rects; +pRectEnd =&pRect[region-> num_rects - 1]; region-> +extents.left=pRect->left; region->extents.top=pRect +->top;region->extents.right =pRectEnd-> right; region-> +extents.bottom=pRectEnd->bottom ;while(pRect <= pRectEnd){if ( +pRect->left< region->extents.left) region->extents.left= pRect->left; +if (pRect-> right>region->extents.right)region->extents.right= pRect->right +;pRect++; }} /*handle an overlapping band for intersect _region */ +static int intersect_overlapping(struct region *pReg, const +rectangle_t* r1,const rectangle_t *r1End,const +rectangle_t *r2, const +rectangle_t*r2End,int top,int bottom){int left,right;while ((r1 != r1End)&&(r2!= +r2End)){left=max(r1->left,r2->left);right=min(r1->right,r2->right);if(left<right +){rectangle_t*rect = add_rect(pReg);if(!rect)return 0;rect->left=left;rect->top= +top;rect->right=right;rect->bottom=bottom;}if (r1->right<r2->right)r1++;else if( +r2->right<r1->right)r2++;else{r1++;r2++;}}return 1;} /* handle a non-overlapping +band for subtract_region*/static int subtract_non_overlapping(struct region*pReg +,const rectangle_t*r,const rectangle_t*rEnd, int top,int bottom){while(r!=rEnd){ + rectangle_t*rect =add_rect(pReg); + if(!rect) return 0;rect->left=r-> + left;rect->top = top;rect->right= + r->right; rect-> bottom = bottom; + r++;} return 1;} /* handle an + overlapping band for subtract_region */ + static int subtract_overlapping(struct region *pReg, + const rectangle_t*r1, const rectangle_t*r1End, const + rectangle_t *r2,const rectangle_t *r2End,int top,int + bottom){int left=r1->left; while((r1!=r1End + )&&(r2!=r2End)){ if (r2->right <= + left) r2++; else if (r2->left <= + left){left =r2-> right; if(left>= + r1->right){r1++; if(r1!=r1End)left=r1->left + ;}else r2++;}else if(r2->left<r1->right){rectangle_t + *rect=add_rect(pReg); if(!rect)return 0; rect->left= + left;rect->top=top;rect->right=r2->left;rect->bottom + =bottom;left=r2->right;if (left>=r1->right + ){r1++; if(r1 != r1End) left=r1-> + left;}else r2++; } else {if (r1-> + right > left ) { rectangle_t*rect + =add_rect(pReg); if(!rect)return 0;rect + ->left=left;rect->top=top;rect->right=r1->right;rect + ->bottom=bottom;}r1++;if(r1!=r1End) left=r1->left;}} + while(r1!=r1End){rectangle_t*rect=add_rect(pReg);if( + !rect)return 0;rect->left= left; rect->top= + top;rect->right= r1->right;rect-> + bottom=bottom;r1 ++;if(r1!=r1End) + left= r1->left;} return 1;}/*handle a + non-overlapping band for union_region*/static int + union_non_overlapping( struct region *pReg, const + rectangle_t *r, const rectangle_t *rEnd, int top,int + bottom){while(r != rEnd){rectangle_t *rect=add_rect( + pReg);if(!rect)return 0; rect->left = r-> + left; rect->top= top;rect->right= + r->right; rect-> bottom=bottom; r + ++;} return 1;} /* handle an overlapping band for union_region */ static int + union_overlapping(struct region*pReg,const rectangle_t *r1,const rectangle_t + *r1End, const rectangle_t *r2,const rectangle_t *r2End,int top, int bottom){ + #define MERGERECT(r)if((pReg->num_rects!=0)&&(pReg->rects[pReg->num_rects-1\ + ].top==top)&&(pReg->rects[ pReg->num_rects-1].bottom\ + ==bottom) && (pReg->rects[ pReg->num_rects -1].right\ + >=r->left)){if(pReg->rects [pReg->num_rects-1].right<\ + r->right){pReg->rects[pReg ->num_rects-1].right = r->\ + right;}}else {rectangle_t* rect = add_rect(pReg);if(\ + !rect)return 0;rect->top= top;rect->bottom=bottom;\ + rect->left=r->left;rect ->right = r->right;}r++; + while((r1!=r1End)&&(r2 !=r2End)){if(r1->left<r2 + ->left){MERGERECT(r1);} else{MERGERECT(r2);}}if( + r1!=r1End){do{MERGERECT(r1);}while(r1!= + r1End);}else while (r2!=r2End){ + MERGERECT(r2);}return 1; + #undef MERGERECT + }/*create an empty region*/ + struct region*create_empty_region(void + ){struct region*region;if(!(region=mem_alloc(sizeof + (*region))))return NULL;if (!(region->rects=mem_alloc + (RGN_DEFAULT_RECTS *sizeof (*region->rects )))){free( + region);return NULL;}region ->size = RGN_DEFAULT_RECTS; + region->num_rects=0;region ->extents.left=0; region-> + extents.top = 0; region-> extents.right = 0;region-> + extents.bottom = 0; return region;}/* create a region + from request data */struct region* create_region_from_req_data + (const void*data,data_size_t size){ unsigned int alloc_rects; + struct region*region;const rectangle_t *rects = data; + int nb_rects = size/sizeof( rectangle_t ); /* special + case: empty region can be specified by a single all- + zero rectangle*/if(nb_rects== 1&&!memcmp(rects,&empty_rect + ,sizeof(empty_rect)))nb_rects =0;if(!validate_rectangles + (rects,nb_rects)){set_error (STATUS_INVALID_PARAMETER) + ;return NULL;}if(!(region= mem_alloc(sizeof(*region) + ))) return NULL; alloc_rects = max(nb_rects, + RGN_DEFAULT_RECTS);if(!(region->rects + = mem_alloc( alloc_rects * + sizeof(*region-> + rects)))){free(region);return + NULL;}region->size=alloc_rects; region-> + num_rects=nb_rects;memcpy (region->rects, rects, + nb_rects*sizeof(*rects)); set_region_extents(region + );return region;}/*free a region */void free_region + (struct region*region){free (region->rects);free(region + );}/*set region to a simple rectangle*/void set_region_rect + (struct region *region, const rectangle_t*rect){if + (!is_rect_empty ( rect )){ region ->num_rects=1;region->rects + [0]=region->extents=*rect; }else{ region->num_rects=0;region + ->extents=empty_rect;}} /* retrieve the region data + for sending to the client*/ rectangle_t*get_region_data + (const struct region*region ,data_size_t max_size, + data_size_t *total_size ){ const rectangle_t *data = + region->rects;if(!(*total_size =region->num_rects*sizeof( + rectangle_t))){/* return a single empty rect for empty + regions*/*total_size=sizeof (empty_rect);data=&empty_rect + ;}if (max_size >= *total_size)return memdup(data,* + total_size);set_error(STATUS_BUFFER_OVERFLOW + );return NULL;}/*retrieve the region + data for sending to the + client and free + the region at the same time + */rectangle_t*get_region_data_and_free + (struct region *region, data_size_t max_size, + data_size_t*total_size) {rectangle_t*ret=region + ->rects;if(!(*total_size =region->num_rects*sizeof + (rectangle_t))){/* return a single empty rect for + empty regions*/*total_size =sizeof( empty_rect );if( + max_size>=sizeof(empty_rect )){ret=memdup(&empty_rect, + sizeof( empty_rect ));free( region->rects);}}if(max_size + <*total_size){free( region ->rects); set_error( + STATUS_BUFFER_OVERFLOW ); ret = NULL;}free(region);return + ret;} /* check if a given region is empty*/int is_region_empty + (const struct region*region ){return region->num_rects == 0;}/* + get the extents rect of a region */void get_region_extents + (const struct region*region ,rectangle_t*rect){*rect= + region->extents;}/* add an offset to a region */void + offset_region(struct region *region, int x, int y ){ + rectangle_t*rect,*end;if(! region->num_rects)return; + for(rect=region->rects,end =rect+region->num_rects; + rect<end;rect++)offset_rect(rect,x,y);offset_rect( + ®ion->extents,x,y);}/*mirror a region + relative to a window client + rect */ void + mirror_region(const rectangle_t + *client_rect,struct region*region){int start + ,end,i,j;for(start=0;start <region->num_rects;start= + end+1){for(end=start;end <region->num_rects-1;end + ++)if(region->rects[end+1] .top!=region->rects[end]. + top)break;for(i=start,j=end ;i<j;i++,j--){rectangle_t + rect=region->rects[j];region ->rects[i]=region->rects[j + ];region->rects[j] = rect; mirror_rect(client_rect,& + region->rects[j]);mirror_rect (client_rect,®ion->rects + [i]);}if(i==j)mirror_rect( client_rect,®ion->rects + [i]);} mirror_rect( client_rect, ®ion->extents );}/* scale a region for a + given dpi factor */ void scale_region( struct region * region, unsigned int + + + + + + + + + + dpi_from,unsigned int dpi_to ){rectangle_t + *rect,*end;if(!region->num_rects)return;for( + rect=region->rects, end=rect+region->num_rects + ;rect<end;rect++)scale_dpi_rect(rect,dpi_from, + dpi_to); scale_dpi_rect(®ion->extents, + dpi_from,dpi_to);} /* make a copy of a region; + returns dst or NULL on error */ struct region* + copy_region ( struct region *dst, const struct + region*src){if(dst == src)return dst; if(dst-> + size<src->num_rects){rectangle_t*rect=realloc( + dst->rects,src->num_rects*sizeof(*rect)); if(! + rect){set_error(STATUS_NO_MEMORY);return NULL; + }dst->rects=rect;dst->size=src->num_rects;}dst + ->num_rects=src->num_rects; dst->extents=src-> + extents; memcpy( dst->rects,src->rects,src-> + num_rects*sizeof(*dst->rects)); return dst;} + /* compute the intersection of two regions + into dst, which can be one of the source + regions*/struct region*intersect_region( + struct region*dst,const struct region + *src1,const struct region *src2) + {if (!src1->num_rects||! + src2->num_rects||! + EXTENTCHECK( + &src1-> + extents + ,&src2-> + extents + )){dst-> + num_rects + =0;dst-> + extents + .left=0 + ;dst-> + extents + .top=0 + ;dst-> + extents + .right= + 0;dst-> + extents + .bottom= + 0;return + dst;}if(! + region_op + (dst,src1,src2 + ,intersect_overlapping,NULL, + NULL))return NULL;set_region_extents(dst);return dst;}
-#define RGN_DEFAULT_RECTS 2
-#define EXTENTCHECK(r1, r2) \ - ((r1)->right > (r2)->left && \ - (r1)->left < (r2)->right && \ - (r1)->bottom > (r2)->top && \ - (r1)->top < (r2)->bottom)
-typedef int (*overlap_func_t)( struct region *reg, const rectangle_t *r1, const rectangle_t *r1End, - const rectangle_t *r2, const rectangle_t *r2End, int top, int bottom ); -typedef int (*non_overlap_func_t)( struct region *reg, const rectangle_t *r, - const rectangle_t *rEnd, int top, int bottom );
-static const rectangle_t empty_rect; /* all-zero rectangle for empty regions */ - -/* add a rectangle to a region */ -static inline rectangle_t *add_rect( struct region *reg ) -{ - if (reg->num_rects >= reg->size) - { - rectangle_t *new_rect = realloc( reg->rects, 2 * sizeof(rectangle_t) * reg->size ); - if (!new_rect) - { - set_error( STATUS_NO_MEMORY ); - return NULL; - } - reg->rects = new_rect; - reg->size *= 2; - } - return reg->rects + reg->num_rects++; -} - -/* make sure all the rectangles are valid and that the region is properly y-x-banded */ -static inline int validate_rectangles( const rectangle_t *rects, unsigned int nb_rects ) -{ - const rectangle_t *ptr, *end; - - for (ptr = rects, end = rects + nb_rects; ptr < end; ptr++) - { - if (is_rect_empty( ptr )) return 0; /* empty rectangle */ - if (ptr == end - 1) break; - if (ptr[0].top == ptr[1].top) /* same band */ - { - if (ptr[0].bottom != ptr[1].bottom) return 0; /* not same y extent */ - if (ptr[0].right >= ptr[1].left) return 0; /* not properly x ordered */ - } - else /* new band */ - { - if (ptr[0].bottom > ptr[1].top) return 0; /* not properly y ordered */ - } - } - return 1; -} - -/* attempt to merge the rects in the current band with those in the */ -/* previous one. Used only by region_op. */ -static int coalesce_region( struct region *pReg, int prevStart, int curStart ) -{ - int curNumRects; - rectangle_t *pRegEnd = &pReg->rects[pReg->num_rects]; - rectangle_t *pPrevRect = &pReg->rects[prevStart]; - rectangle_t *pCurRect = &pReg->rects[curStart]; - int prevNumRects = curStart - prevStart; - int bandtop = pCurRect->top; - - for (curNumRects = 0; - (pCurRect != pRegEnd) && (pCurRect->top == bandtop); - curNumRects++) - { - pCurRect++; - } - - if (pCurRect != pRegEnd) - { - pRegEnd--; - while (pRegEnd[-1].top == pRegEnd->top) pRegEnd--; - curStart = pRegEnd - pReg->rects; - pRegEnd = pReg->rects + pReg->num_rects; - } - - if ((curNumRects == prevNumRects) && (curNumRects != 0)) - { - pCurRect -= curNumRects; - if (pPrevRect->bottom == pCurRect->top) - { - do - { - if ((pPrevRect->left != pCurRect->left) || - (pPrevRect->right != pCurRect->right)) return curStart; - pPrevRect++; - pCurRect++; - prevNumRects -= 1; - } while (prevNumRects != 0); - - pReg->num_rects -= curNumRects; - pCurRect -= curNumRects; - pPrevRect -= curNumRects; - - do - { - pPrevRect->bottom = pCurRect->bottom; - pPrevRect++; - pCurRect++; - curNumRects -= 1; - } while (curNumRects != 0); - - if (pCurRect == pRegEnd) curStart = prevStart; - else do { *pPrevRect++ = *pCurRect++; } while (pCurRect != pRegEnd); - - } - } - return curStart; -} - -/* apply an operation to two regions */ -/* check the GDI version of the code for explanations */ -static int region_op( struct region *newReg, const struct region *reg1, const struct region *reg2, - overlap_func_t overlap_func, - non_overlap_func_t non_overlap1_func, - non_overlap_func_t non_overlap2_func ) -{ - int ybot, ytop, top, bot, prevBand, curBand; - const rectangle_t *r1BandEnd, *r2BandEnd; - - const rectangle_t *r1 = reg1->rects; - const rectangle_t *r2 = reg2->rects; - const rectangle_t *r1End = r1 + reg1->num_rects; - const rectangle_t *r2End = r2 + reg2->num_rects; - - rectangle_t *new_rects, *old_rects = newReg->rects; - int new_size, ret = 0; - - new_size = max( reg1->num_rects, reg2->num_rects ) * 2; - if (!(new_rects = mem_alloc( new_size * sizeof(*newReg->rects) ))) return 0; - - newReg->size = new_size; - newReg->rects = new_rects; - newReg->num_rects = 0; - - if (reg1->extents.top < reg2->extents.top) - ybot = reg1->extents.top; - else - ybot = reg2->extents.top; - - prevBand = 0; - - do - { - curBand = newReg->num_rects; - - r1BandEnd = r1; - while ((r1BandEnd != r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++; - - r2BandEnd = r2; - while ((r2BandEnd != r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++; - - if (r1->top < r2->top) - { - top = max(r1->top,ybot); - bot = min(r1->bottom,r2->top); - - if ((top != bot) && non_overlap1_func) - { - if (!non_overlap1_func( newReg, r1, r1BandEnd, top, bot )) goto done; - } - - ytop = r2->top; - } - else if (r2->top < r1->top) - { - top = max(r2->top,ybot); - bot = min(r2->bottom,r1->top); - - if ((top != bot) && non_overlap2_func) - { - if (!non_overlap2_func( newReg, r2, r2BandEnd, top, bot )) goto done; - } - - ytop = r1->top; - } - else - { - ytop = r1->top; - } - - if (newReg->num_rects != curBand) - prevBand = coalesce_region(newReg, prevBand, curBand); - - ybot = min(r1->bottom, r2->bottom); - curBand = newReg->num_rects; - if (ybot > ytop) - { - if (!overlap_func( newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot )) goto done; - } - - if (newReg->num_rects != curBand) - prevBand = coalesce_region(newReg, prevBand, curBand); - - if (r1->bottom == ybot) r1 = r1BandEnd; - if (r2->bottom == ybot) r2 = r2BandEnd; - } while ((r1 != r1End) && (r2 != r2End)); - - curBand = newReg->num_rects; - if (r1 != r1End) - { - if (non_overlap1_func) - { - do - { - r1BandEnd = r1; - while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top)) r1BandEnd++; - if (!non_overlap1_func( newReg, r1, r1BandEnd, max(r1->top,ybot), r1->bottom )) - goto done; - r1 = r1BandEnd; - } while (r1 != r1End); - } - } - else if ((r2 != r2End) && non_overlap2_func) - { - do - { - r2BandEnd = r2; - while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top)) r2BandEnd++; - if (!non_overlap2_func( newReg, r2, r2BandEnd, max(r2->top,ybot), r2->bottom )) - goto done; - r2 = r2BandEnd; - } while (r2 != r2End); - } - - if (newReg->num_rects != curBand) coalesce_region(newReg, prevBand, curBand); - - if ((newReg->num_rects < (newReg->size / 2)) && (newReg->size > 2)) - { - new_size = max( newReg->num_rects, RGN_DEFAULT_RECTS ); - if ((new_rects = realloc( newReg->rects, sizeof(*newReg->rects) * new_size ))) - { - newReg->rects = new_rects; - newReg->size = new_size; - } - } - ret = 1; -done: - free( old_rects ); - return ret; -} - -/* recalculate the extents of a region */ -static void set_region_extents( struct region *region ) -{ - rectangle_t *pRect, *pRectEnd; - - if (region->num_rects == 0) - { - region->extents.left = 0; - region->extents.top = 0; - region->extents.right = 0; - region->extents.bottom = 0; - return; - } - - pRect = region->rects; - pRectEnd = &pRect[region->num_rects - 1]; - - region->extents.left = pRect->left; - region->extents.top = pRect->top; - region->extents.right = pRectEnd->right; - region->extents.bottom = pRectEnd->bottom; - - while (pRect <= pRectEnd) - { - if (pRect->left < region->extents.left) region->extents.left = pRect->left; - if (pRect->right > region->extents.right) region->extents.right = pRect->right; - pRect++; - } -} - -/* handle an overlapping band for intersect_region */ -static int intersect_overlapping( struct region *pReg, - const rectangle_t *r1, const rectangle_t *r1End, - const rectangle_t *r2, const rectangle_t *r2End, - int top, int bottom ) - -{ - int left, right; - - while ((r1 != r1End) && (r2 != r2End)) - { - left = max(r1->left, r2->left); - right = min(r1->right, r2->right); - - if (left < right) - { - rectangle_t *rect = add_rect( pReg ); - if (!rect) return 0; - rect->left = left; - rect->top = top; - rect->right = right; - rect->bottom = bottom; - } - - if (r1->right < r2->right) r1++; - else if (r2->right < r1->right) r2++; - else - { - r1++; - r2++; - } - } - return 1; -} - -/* handle a non-overlapping band for subtract_region */ -static int subtract_non_overlapping( struct region *pReg, const rectangle_t *r, - const rectangle_t *rEnd, int top, int bottom ) -{ - while (r != rEnd) - { - rectangle_t *rect = add_rect( pReg ); - if (!rect) return 0; - rect->left = r->left; - rect->top = top; - rect->right = r->right; - rect->bottom = bottom; - r++; - } - return 1; -} - -/* handle an overlapping band for subtract_region */ -static int subtract_overlapping( struct region *pReg, - const rectangle_t *r1, const rectangle_t *r1End, - const rectangle_t *r2, const rectangle_t *r2End, - int top, int bottom ) -{ - int left = r1->left; - - while ((r1 != r1End) && (r2 != r2End)) - { - if (r2->right <= left) r2++; - else if (r2->left <= left) - { - left = r2->right; - if (left >= r1->right) - { - r1++; - if (r1 != r1End) - left = r1->left; - } - else r2++; - } - else if (r2->left < r1->right) - { - rectangle_t *rect = add_rect( pReg ); - if (!rect) return 0; - rect->left = left; - rect->top = top; - rect->right = r2->left; - rect->bottom = bottom; - left = r2->right; - if (left >= r1->right) - { - r1++; - if (r1 != r1End) - left = r1->left; - } - else r2++; - } - else - { - if (r1->right > left) - { - rectangle_t *rect = add_rect( pReg ); - if (!rect) return 0; - rect->left = left; - rect->top = top; - rect->right = r1->right; - rect->bottom = bottom; - } - r1++; - if (r1 != r1End) - left = r1->left; - } - } - - while (r1 != r1End) - { - rectangle_t *rect = add_rect( pReg ); - if (!rect) return 0; - rect->left = left; - rect->top = top; - rect->right = r1->right; - rect->bottom = bottom; - r1++; - if (r1 != r1End) left = r1->left; - } - return 1; -} - -/* handle a non-overlapping band for union_region */ -static int union_non_overlapping( struct region *pReg, const rectangle_t *r, - const rectangle_t *rEnd, int top, int bottom ) -{ - while (r != rEnd) - { - rectangle_t *rect = add_rect( pReg ); - if (!rect) return 0; - rect->left = r->left; - rect->top = top; - rect->right = r->right; - rect->bottom = bottom; - r++; - } - return 1; -} - -/* handle an overlapping band for union_region */ -static int union_overlapping( struct region *pReg, - const rectangle_t *r1, const rectangle_t *r1End, - const rectangle_t *r2, const rectangle_t *r2End, - int top, int bottom ) -{ -#define MERGERECT(r) \ - if ((pReg->num_rects != 0) && \ - (pReg->rects[pReg->num_rects-1].top == top) && \ - (pReg->rects[pReg->num_rects-1].bottom == bottom) && \ - (pReg->rects[pReg->num_rects-1].right >= r->left)) \ - { \ - if (pReg->rects[pReg->num_rects-1].right < r->right) \ - { \ - pReg->rects[pReg->num_rects-1].right = r->right; \ - } \ - } \ - else \ - { \ - rectangle_t *rect = add_rect( pReg ); \ - if (!rect) return 0; \ - rect->top = top; \ - rect->bottom = bottom; \ - rect->left = r->left; \ - rect->right = r->right; \ - } \ - r++; - - while ((r1 != r1End) && (r2 != r2End)) - { - if (r1->left < r2->left) - { - MERGERECT(r1); - } - else - { - MERGERECT(r2); - } - } - - if (r1 != r1End) - { - do - { - MERGERECT(r1); - } while (r1 != r1End); - } - else while (r2 != r2End) - { - MERGERECT(r2); - } - return 1; -#undef MERGERECT -} - - -/* create an empty region */ -struct region *create_empty_region(void) -{ - struct region *region; - - if (!(region = mem_alloc( sizeof(*region) ))) return NULL; - if (!(region->rects = mem_alloc( RGN_DEFAULT_RECTS * sizeof(*region->rects) ))) - { - free( region ); - return NULL; - } - region->size = RGN_DEFAULT_RECTS; - region->num_rects = 0; - region->extents.left = 0; - region->extents.top = 0; - region->extents.right = 0; - region->extents.bottom = 0; - return region; -} - -/* create a region from request data */ -struct region *create_region_from_req_data( const void *data, data_size_t size ) -{ - unsigned int alloc_rects; - struct region *region; - const rectangle_t *rects = data; - int nb_rects = size / sizeof(rectangle_t); - - /* special case: empty region can be specified by a single all-zero rectangle */ - if (nb_rects == 1 && !memcmp( rects, &empty_rect, sizeof(empty_rect) )) nb_rects = 0; - - if (!validate_rectangles( rects, nb_rects )) - { - set_error( STATUS_INVALID_PARAMETER ); - return NULL; - } - - if (!(region = mem_alloc( sizeof(*region) ))) return NULL; - - alloc_rects = max( nb_rects, RGN_DEFAULT_RECTS ); - if (!(region->rects = mem_alloc( alloc_rects * sizeof(*region->rects) ))) - { - free( region ); - return NULL; - } - region->size = alloc_rects; - region->num_rects = nb_rects; - memcpy( region->rects, rects, nb_rects * sizeof(*rects) ); - set_region_extents( region ); - return region; -} - -/* free a region */ -void free_region( struct region *region ) -{ - free( region->rects ); - free( region ); -} - -/* set region to a simple rectangle */ -void set_region_rect( struct region *region, const rectangle_t *rect ) -{ - if (!is_rect_empty( rect )) - { - region->num_rects = 1; - region->rects[0] = region->extents = *rect; - } - else - { - region->num_rects = 0; - region->extents = empty_rect; - } -} - -/* retrieve the region data for sending to the client */ -rectangle_t *get_region_data( const struct region *region, data_size_t max_size, data_size_t *total_size ) -{ - const rectangle_t *data = region->rects; - - if (!(*total_size = region->num_rects * sizeof(rectangle_t))) - { - /* return a single empty rect for empty regions */ - *total_size = sizeof(empty_rect); - data = &empty_rect; - } - if (max_size >= *total_size) return memdup( data, *total_size ); - set_error( STATUS_BUFFER_OVERFLOW ); - return NULL; -} - -/* retrieve the region data for sending to the client and free the region at the same time */ -rectangle_t *get_region_data_and_free( struct region *region, data_size_t max_size, data_size_t *total_size ) -{ - rectangle_t *ret = region->rects; - - if (!(*total_size = region->num_rects * sizeof(rectangle_t))) - { - /* return a single empty rect for empty regions */ - *total_size = sizeof(empty_rect); - if (max_size >= sizeof(empty_rect)) - { - ret = memdup( &empty_rect, sizeof(empty_rect) ); - free( region->rects ); - } - } - - if (max_size < *total_size) - { - free( region->rects ); - set_error( STATUS_BUFFER_OVERFLOW ); - ret = NULL; - } - free( region ); - return ret; -} - -/* check if a given region is empty */ -int is_region_empty( const struct region *region ) -{ - return region->num_rects == 0; -} - - -/* get the extents rect of a region */ -void get_region_extents( const struct region *region, rectangle_t *rect ) -{ - *rect = region->extents; -} - -/* add an offset to a region */ -void offset_region( struct region *region, int x, int y ) -{ - rectangle_t *rect, *end; - - if (!region->num_rects) return; - for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++) - offset_rect( rect, x, y ); - offset_rect( ®ion->extents, x, y ); -} - -/* mirror a region relative to a window client rect */ -void mirror_region( const rectangle_t *client_rect, struct region *region ) -{ - int start, end, i, j; - - for (start = 0; start < region->num_rects; start = end + 1) - { - for (end = start; end < region->num_rects - 1; end++) - if (region->rects[end + 1].top != region->rects[end].top) break; - for (i = start, j = end; i < j; i++, j--) - { - rectangle_t rect = region->rects[j]; - region->rects[i] = region->rects[j]; - region->rects[j] = rect; - mirror_rect( client_rect, ®ion->rects[j] ); - mirror_rect( client_rect, ®ion->rects[i] ); - } - if (i == j) mirror_rect( client_rect, ®ion->rects[i] ); - } - mirror_rect( client_rect, ®ion->extents ); -} - - -/* scale a region for a given dpi factor */ -void scale_region( struct region *region, unsigned int dpi_from, unsigned int dpi_to ) -{ - rectangle_t *rect, *end; - - if (!region->num_rects) return; - for (rect = region->rects, end = rect + region->num_rects; rect < end; rect++) - scale_dpi_rect( rect, dpi_from, dpi_to ); - scale_dpi_rect( ®ion->extents, dpi_from, dpi_to ); -} - - -/* make a copy of a region; returns dst or NULL on error */ -struct region *copy_region( struct region *dst, const struct region *src ) -{ - if (dst == src) return dst; - - if (dst->size < src->num_rects) - { - rectangle_t *rect = realloc( dst->rects, src->num_rects * sizeof(*rect) ); - if (!rect) - { - set_error( STATUS_NO_MEMORY ); - return NULL; - } - dst->rects = rect; - dst->size = src->num_rects; - } - dst->num_rects = src->num_rects; - dst->extents = src->extents; - memcpy( dst->rects, src->rects, src->num_rects * sizeof(*dst->rects) ); - return dst; -} - -/* compute the intersection of two regions into dst, which can be one of the source regions */ -struct region *intersect_region( struct region *dst, const struct region *src1, - const struct region *src2 ) -{ - if (!src1->num_rects || !src2->num_rects || !EXTENTCHECK(&src1->extents, &src2->extents)) - { - dst->num_rects = 0; - dst->extents.left = 0; - dst->extents.top = 0; - dst->extents.right = 0; - dst->extents.bottom = 0; - return dst; - } - if (!region_op( dst, src1, src2, intersect_overlapping, NULL, NULL )) return NULL; - set_region_extents( dst ); - return dst; -}
/* compute the subtraction of two regions into dst, which can be one of the source regions */ struct region *subtract_region( struct region *dst, const struct region *src1,