[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(
+                    &region->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,&region->rects
+  [i]);}if(i==j)mirror_rect(                        client_rect,&region->rects
+  [i]);} mirror_rect( client_rect, &region->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(&region->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( &region->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, &region->rects[i] );
-        }
-        if (i == j) mirror_rect( client_rect, &region->rects[i] );
-    }
-    mirror_rect( client_rect, &region->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( &region->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