home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / utility / macregion.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  6.8 KB  |  287 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. //    macregion.c
  20.  
  21. //    FE specific region operations
  22.  
  23.     // Netscape
  24. #include "client.h"
  25. #include "fe_rgn.h"
  26.     // system
  27. #include <Quickdraw.h>
  28.  
  29. #ifdef LAYERS
  30.  
  31. FE_Region FE_CreateRegion()
  32. {
  33.     RgnHandle rgnH = NewRgn();
  34.     
  35.     // BUGBUG What's the right thing to do for memory/allocation errors.
  36.     // Assertions are not the right way to go. 
  37.     XP_ASSERT(rgnH != nil);
  38.     
  39.     return (FE_Region)rgnH;
  40. }
  41.  
  42. /* Creates a region from a rectangle. Returns */
  43. /* NULL if region can't be created.           */
  44. FE_Region 
  45. FE_CreateRectRegion(XP_Rect *rect)
  46. {
  47.     RgnHandle rgnH;
  48.     
  49.     XP_ASSERT(rect != nil);
  50.     
  51.     rgnH = NewRgn();
  52.         
  53.     XP_ASSERT(rgnH != nil);
  54.  
  55.     SetRectRgn(rgnH, rect->left, rect->top, rect->right, rect->bottom);
  56.     
  57.     return (FE_Region)rgnH;
  58. }
  59.  
  60. /* Destroys region. */
  61. void 
  62. FE_DestroyRegion(FE_Region region)
  63. {
  64.     DisposeRgn((RgnHandle)region);
  65. }
  66.  
  67. /* Makes a copy of a region. If dst is NULL, creates a new region */
  68. FE_Region 
  69. FE_CopyRegion(FE_Region src, FE_Region dst)
  70. {
  71.     RgnHandle copyRgnH;
  72.     
  73.     XP_ASSERT(src);
  74.     
  75.     if (dst != nil) 
  76.         copyRgnH = (RgnHandle)dst;
  77.     else {
  78.         copyRgnH = NewRgn();
  79.         XP_ASSERT(copyRgnH != nil);
  80.     }
  81.     
  82.     CopyRgn((RgnHandle)src, copyRgnH);
  83.     
  84.     return (FE_Region)copyRgnH;
  85. }
  86.  
  87. /* Set an existing region to a rectangle */
  88. FE_Region 
  89. FE_SetRectRegion(FE_Region region, XP_Rect *rect)
  90. {
  91.     XP_ASSERT(region);
  92.     XP_ASSERT(rect);
  93.     
  94.     SetRectRgn((RgnHandle)region, rect->left, rect->top, rect->right, rect->bottom);
  95.     
  96.     return region;
  97. }
  98.  
  99. /* dst = src1 intersect sr2       */
  100. /* dst can be one of src1 or src2 */
  101. void 
  102. FE_IntersectRegion(FE_Region src1, FE_Region src2, FE_Region dst)
  103. {
  104.     XP_ASSERT(src1);
  105.     XP_ASSERT(src2);
  106.     XP_ASSERT(dst);
  107.     
  108.     SectRgn((RgnHandle)src1, (RgnHandle)src2, (RgnHandle)dst);
  109. }
  110.  
  111. /* dst = src1 union src2          */
  112. /* dst can be one of src1 or src2 */
  113. void FE_UnionRegion(FE_Region src1, FE_Region src2, FE_Region dst)
  114. {
  115.     XP_ASSERT(src1);
  116.     XP_ASSERT(src2);
  117.     XP_ASSERT(dst);
  118.     
  119.     UnionRgn((RgnHandle)src1, (RgnHandle)src2, (RgnHandle)dst);
  120. }
  121.  
  122. /* dst = src1 - src2              */
  123. /* dst can be one of src1 or src2 */
  124. void FE_SubtractRegion(FE_Region src1, FE_Region src2, FE_Region dst)
  125. {
  126.     XP_ASSERT(src1);
  127.     XP_ASSERT(src2);
  128.     XP_ASSERT(dst);
  129.     
  130.     DiffRgn((RgnHandle)src1, (RgnHandle)src2, (RgnHandle)dst);
  131. }
  132.  
  133. /* Returns TRUE if the region contains no pixels */
  134. XP_Bool 
  135. FE_IsEmptyRegion(FE_Region region)
  136. {
  137.     XP_ASSERT(region);
  138.     
  139.     return (XP_Bool)EmptyRgn((RgnHandle)region);
  140. }
  141.  
  142. /* Returns the bounding rectangle of the region */
  143. void 
  144. FE_GetRegionBoundingBox(FE_Region region, XP_Rect *bbox)
  145. {
  146.     RgnHandle rgnH = (RgnHandle)region;
  147.     
  148.     XP_ASSERT(region);
  149.     XP_ASSERT(bbox);
  150.  
  151.     bbox->left = (**rgnH).rgnBBox.left;
  152.     bbox->top = (**rgnH).rgnBBox.top;
  153.     bbox->right = (**rgnH).rgnBBox.right;
  154.     bbox->bottom = (**rgnH).rgnBBox.bottom;
  155. }
  156.  
  157. /* TRUE if rgn1 == rgn2 */
  158. XP_Bool
  159. FE_IsEqualRegion(FE_Region rgn1, FE_Region rgn2)
  160. {
  161.     XP_ASSERT(rgn1);
  162.     XP_ASSERT(rgn2);
  163.     
  164.     return (XP_Bool)EqualRgn((RgnHandle)rgn1, (RgnHandle)rgn2);
  165. }
  166.  
  167. /* Moves a region by the specified offsets */
  168. void 
  169. FE_OffsetRegion(FE_Region region, int32 xOffset, int32 yOffset)
  170. {
  171.     XP_ASSERT(region);
  172.     
  173.     OffsetRgn((RgnHandle)region, xOffset, yOffset);
  174. }
  175.  
  176. /* Is any part of the rectangle in the specified region */
  177. XP_Bool
  178. FE_RectInRegion(FE_Region region, XP_Rect *rect)
  179. {
  180.     Rect macRect;
  181.     
  182.     XP_ASSERT(region);
  183.     XP_ASSERT(rect);
  184.     
  185.     macRect.left = rect->left;
  186.     macRect.top = rect->top;
  187.     macRect.right = rect->right;
  188.     macRect.bottom = rect->bottom;
  189.     
  190.     return (XP_Bool)RectInRgn(&macRect, (RgnHandle)region);
  191. }
  192.  
  193. /* For each rectangle that makes up this region, call the func */
  194. /* This is a minor adaptation of code written by Hugh Fisher
  195.    and published in the RegionToRectangles example in the InfoMac archives.
  196. */
  197. void
  198. FE_ForEachRectInRegion(FE_Region rgn, FE_RectInRegionFunc func, void *closure)
  199. {
  200. #define EndMark     32767
  201. #define MaxY        32767
  202. #define StackMax    1024
  203.  
  204.     typedef struct {
  205.         short    size;
  206.         Rect    bbox;
  207.         short    data[];
  208.         } ** Internal;
  209.     
  210.     Internal region;
  211.     short     width, xAdjust, y, index, x1, x2, x;
  212.     XP_Rect     box;
  213.     short     stackStorage[1024];
  214.     short *     buffer;
  215.     RgnHandle r = (RgnHandle)rgn;
  216.     
  217.     region = (Internal)r;
  218.     
  219.     /* Check for plain rectangle */
  220.     if ((**region).size == 10) {
  221.         box.left = (**region).bbox.left;
  222.         box.top = (**region).bbox.top;
  223.         box.right = (**region).bbox.right;
  224.         box.bottom = (**region).bbox.bottom;
  225.         func(closure, &box);
  226.         return;
  227.     }
  228.     /* Got to scale x coordinates into range 0..something */
  229.     xAdjust = (**region).bbox.left;
  230.     width = (**region).bbox.right - xAdjust;
  231.     /* Most regions will be less than 1024 pixels wide */
  232.     if (width < StackMax)
  233.         buffer = stackStorage;
  234.     else {
  235.         buffer = (short *)NewPtr(width * 2);
  236.         if (buffer == NULL)
  237.             /* Truly humungous region or very low on memory.
  238.                Quietly doing nothing seems to be the
  239.                traditional Quickdraw response. */
  240.             return;
  241.     }
  242.     /* Initialise scan line list to bottom edges */
  243.     for (x = (**region).bbox.left; x < (**region).bbox.right; x++)
  244.         buffer[x - xAdjust] = MaxY;
  245.     index = 0;
  246.     /* Loop until we hit an empty scan line */
  247.     while ((**region).data[index] != EndMark) {
  248.         y = (**region).data[index];
  249.         index ++;
  250.         /* Loop through horizontal runs on this line */
  251.         while ((**region).data[index] != EndMark) {
  252.             x1 = (**region).data[index];
  253.             index ++;
  254.             x2 = (**region).data[index];
  255.             index ++;
  256.             x = x1;
  257.             while (x < x2) {
  258.                 if (buffer[x - xAdjust] < y) {
  259.                     /* We have a bottom edge - how long for? */
  260.                     box.left = x;
  261.                     box.top  = buffer[x - xAdjust];
  262.                     while (x < x2 && buffer[x - xAdjust] == box.top) {
  263.                         buffer[x - xAdjust] = MaxY;
  264.                         x ++;
  265.                     }
  266.                     /* Pass to client proc */
  267.                     box.right  = x;
  268.                     box.bottom = y;
  269.                     func(closure, &box);
  270.                 } else {
  271.                     /* This becomes a top edge */
  272.                     buffer[x - xAdjust] = y;
  273.                     x ++;
  274.                 }
  275.             }
  276.         }
  277.         index ++;
  278.     }
  279.     /* Clean up after ourselves */
  280.     if (width >= StackMax)
  281.         DisposePtr((Ptr)buffer);
  282. #undef EndMark
  283. #undef MaxY
  284. #undef StackMax
  285. }
  286. #endif
  287.