[PATCH] server: Make region.c a little less ugly.
Zebediah Figura
z.figura12 at gmail.com
Thu Apr 1 01:12:28 CDT 2021
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,
--
2.30.2
More information about the wine-devel
mailing list