⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 region.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
 */

VOID FASTCALL
IntDumpRegion(HRGN hRgn)
{
   ROSRGNDATA *Data;

   Data = RGNDATA_LockRgn(hRgn);
   if (Data == NULL)
   {
      DbgPrint("IntDumpRegion called with invalid region!\n");
      return;
   }

   DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
      hRgn,
      Data->rdh.rcBound.left,
      Data->rdh.rcBound.top,
      Data->rdh.rcBound.right,
      Data->rdh.rcBound.bottom,
      Data->rdh.iType);

   RGNDATA_UnlockRgn(Data);
}
#endif /* NDEBUG */

static BOOL FASTCALL REGION_CopyRegion(PROSRGNDATA dst, PROSRGNDATA src)
{
  if(dst != src) //  don't want to copy to itself
  {
    if (dst->rdh.nRgnSize < src->rdh.nCount * sizeof(RECT))
    {
	  PRECT temp;

	  temp = ExAllocatePoolWithTag(PagedPool, src->rdh.nCount * sizeof(RECT), TAG_REGION );
	  if( !temp )
		return FALSE;

	  if( dst->Buffer && dst->Buffer != &dst->rdh.rcBound )
	  	ExFreePool( dst->Buffer );	//free the old buffer
	  dst->Buffer = temp;
      dst->rdh.nRgnSize = src->rdh.nCount * sizeof(RECT);  //size of region buffer
    }
    dst->rdh.nCount = src->rdh.nCount;                 //number of rectangles present in Buffer
    dst->rdh.rcBound.left = src->rdh.rcBound.left;
    dst->rdh.rcBound.top = src->rdh.rcBound.top;
    dst->rdh.rcBound.right = src->rdh.rcBound.right;
    dst->rdh.rcBound.bottom = src->rdh.rcBound.bottom;
    dst->rdh.iType = src->rdh.iType;
    COPY_RECTS(dst->Buffer, src->Buffer, src->rdh.nCount);
  }
  return TRUE;
}

static void FASTCALL REGION_SetExtents (ROSRGNDATA *pReg)
{
    RECT *pRect, *pRectEnd, *pExtents;

    if (pReg->rdh.nCount == 0)
    {
		pReg->rdh.rcBound.left = 0;
		pReg->rdh.rcBound.top = 0;
		pReg->rdh.rcBound.right = 0;
		pReg->rdh.rcBound.bottom = 0;
		pReg->rdh.iType = NULLREGION;
		return;
    }

    pExtents = &pReg->rdh.rcBound;
    pRect = (PRECT)pReg->Buffer;
    pRectEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount - 1;

    /*
     * Since pRect is the first rectangle in the region, it must have the
     * smallest top and since pRectEnd is the last rectangle in the region,
     * it must have the largest bottom, because of banding. Initialize left and
     * right from pRect and pRectEnd, resp., as good things to initialize them
     * to...
     */
    pExtents->left = pRect->left;
    pExtents->top = pRect->top;
    pExtents->right = pRectEnd->right;
    pExtents->bottom = pRectEnd->bottom;

    while (pRect <= pRectEnd)
    {
		if (pRect->left < pExtents->left)
		    pExtents->left = pRect->left;
		if (pRect->right > pExtents->right)
		    pExtents->right = pRect->right;
		pRect++;
    }
    pReg->rdh.iType = (1 == pReg->rdh.nCount ? SIMPLEREGION : COMPLEXREGION);
}


/***********************************************************************
 *           REGION_CropAndOffsetRegion
 */
static BOOL FASTCALL REGION_CropAndOffsetRegion(const PPOINT off, const PRECT rect, PROSRGNDATA rgnSrc, PROSRGNDATA rgnDst)
{
  if(!rect) // just copy and offset
  {
    PRECT xrect;
    if(rgnDst == rgnSrc)
    {
      if(off->x || off->y)
        xrect = (PRECT)rgnDst->Buffer;
      else
        return TRUE;
    }
    else{
      xrect = ExAllocatePoolWithTag(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT), TAG_REGION);
	  if( rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound )
	  	ExFreePool( rgnDst->Buffer ); //free the old buffer. will be assigned to xrect below.
	}

    if(xrect)
    {
      ULONG i;

      if(rgnDst != rgnSrc)
      {
	  	*rgnDst = *rgnSrc;
      }

      if(off->x || off->y)
      {
        for(i = 0; i < rgnDst->rdh.nCount; i++)
        {
          xrect[i].left = ((PRECT)rgnSrc->Buffer + i)->left + off->x;
          xrect[i].right = ((PRECT)rgnSrc->Buffer + i)->right + off->x;
          xrect[i].top = ((PRECT)rgnSrc->Buffer + i)->top + off->y;
          xrect[i].bottom = ((PRECT)rgnSrc->Buffer + i)->bottom + off->y;
        }
        rgnDst->rdh.rcBound.left   += off->x;
        rgnDst->rdh.rcBound.right  += off->x;
        rgnDst->rdh.rcBound.top    += off->y;
        rgnDst->rdh.rcBound.bottom += off->y;
      }
      else
      {
        COPY_RECTS(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount);
      }

	  rgnDst->Buffer = xrect;
    } else
      return FALSE;
  }
  else if ((rect->left >= rect->right) ||
           (rect->top >= rect->bottom) ||
            !EXTENTCHECK(rect, &rgnSrc->rdh.rcBound))
  {
	goto empty;
  }
  else // region box and clipping rect appear to intersect
  {
    PRECT lpr, rpr;
    ULONG i, j, clipa, clipb;
    INT left = rgnSrc->rdh.rcBound.right + off->x;
    INT right = rgnSrc->rdh.rcBound.left + off->x;

    for(clipa = 0; ((PRECT)rgnSrc->Buffer + clipa)->bottom <= rect->top; clipa++)
	//region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
      ; // skip bands above the clipping rectangle

    for(clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++)
      if(((PRECT)rgnSrc->Buffer + clipb)->top >= rect->bottom)
        break;    // and below it

    // clipa - index of the first rect in the first intersecting band
    // clipb - index of the last rect in the last intersecting band

    if((rgnDst != rgnSrc) && (rgnDst->rdh.nCount < (i = (clipb - clipa))))
    {
	  PRECT temp;
	  temp = ExAllocatePoolWithTag( PagedPool, i * sizeof(RECT), TAG_REGION );
      if(!temp)
	      return FALSE;

	  if( rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound )
	  	ExFreePool( rgnDst->Buffer ); //free the old buffer
      rgnDst->Buffer = temp;
      rgnDst->rdh.nCount = i;
	  rgnDst->rdh.nRgnSize = i * sizeof(RECT);
    }

    for(i = clipa, j = 0; i < clipb ; i++)
    {
      // i - src index, j - dst index, j is always <= i for obvious reasons

      lpr = (PRECT)rgnSrc->Buffer + i;

      if(lpr->left < rect->right && lpr->right > rect->left)
      {
	    rpr = (PRECT)rgnDst->Buffer + j;

        rpr->top = lpr->top + off->y;
        rpr->bottom = lpr->bottom + off->y;
        rpr->left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
        rpr->right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;

        if(rpr->left < left) left = rpr->left;
        if(rpr->right > right) right = rpr->right;

        j++;
      }
    }

    if(j == 0) goto empty;

    rgnDst->rdh.rcBound.left = left;
    rgnDst->rdh.rcBound.right = right;

    left = rect->top + off->y;
    right = rect->bottom + off->y;

    rgnDst->rdh.nCount = j--;
    for(i = 0; i <= j; i++) // fixup top band
      if((rgnDst->Buffer + i)->top < left)
        (rgnDst->Buffer + i)->top = left;
      else
        break;

    for(i = j; i >= 0; i--) // fixup bottom band
      if(((PRECT)rgnDst->Buffer + i)->bottom > right)
        ((PRECT)rgnDst->Buffer + i)->bottom = right;
      else
        break;

    rgnDst->rdh.rcBound.top = ((PRECT)rgnDst->Buffer)->top;
    rgnDst->rdh.rcBound.bottom = ((PRECT)rgnDst->Buffer + j)->bottom;

    rgnDst->rdh.iType = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
  }

  return TRUE;

empty:
	if(!rgnDst->Buffer)
	{
	  rgnDst->Buffer = (PRECT)ExAllocatePoolWithTag(PagedPool, RGN_DEFAULT_RECTS * sizeof(RECT), TAG_REGION);
	  if(rgnDst->Buffer){
	    rgnDst->rdh.nCount = RGN_DEFAULT_RECTS;
		rgnDst->rdh.nRgnSize = RGN_DEFAULT_RECTS * sizeof(RECT);
	  }
	  else
	    return FALSE;
	}
	EMPTY_REGION(rgnDst);
	return TRUE;
}

/*!
 * \param
 * hSrc: 	Region to crop and offset.
 * lpRect: 	Clipping rectangle. Can be NULL (no clipping).
 * lpPt:	Points to offset the cropped region. Can be NULL (no offset).
 *
 * hDst: Region to hold the result (a new region is created if it's 0).
 *       Allowed to be the same region as hSrc in which case everything
 *	 will be done in place, with no memory reallocations.
 *
 * \return	hDst if success, 0 otherwise.
 */
HRGN FASTCALL REGION_CropRgn(HRGN hDst, HRGN hSrc, const PRECT lpRect, PPOINT lpPt)
{
  PROSRGNDATA objSrc, rgnDst;
  HRGN hRet = NULL;
  POINT pt = { 0, 0 };

  if( !hDst )
    {
      if( !( hDst = RGNDATA_AllocRgn(1) ) )
	{
	  return 0;
	}
    }

  rgnDst = RGNDATA_LockRgn(hDst);
  if(rgnDst == NULL)
  {
    return NULL;
  }

  objSrc = RGNDATA_LockRgn(hSrc);
  if(objSrc == NULL)
  {
    RGNDATA_UnlockRgn(rgnDst);
    return NULL;
  }
  if(!lpPt)
  	lpPt = &pt;

    if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE)
  { // ve failed cleanup and return
	hRet = NULL;
    }
    else{ // ve are fine. unlock the correct pointer and return correct handle
	hRet = hDst;
  }

  RGNDATA_UnlockRgn(objSrc);
  RGNDATA_UnlockRgn(rgnDst);

  return hRet;
}

/*!
 *      Attempt to merge the rects in the current band with those in the
 *      previous one. Used only by REGION_RegionOp.
 *
 * Results:
 *      The new index for the previous band.
 *
 * \note Side Effects:
 *      If coalescing takes place:
 *          - rectangles in the previous band will have their bottom fields
 *            altered.
 *          - pReg->numRects will be decreased.
 *
 */
static INT FASTCALL REGION_Coalesce (
	     PROSRGNDATA pReg, /* Region to coalesce */
	     INT prevStart,  /* Index of start of previous band */
	     INT curStart    /* Index of start of current band */
) {
    RECT *pPrevRect;          /* Current rect in previous band */
    RECT *pCurRect;           /* Current rect in current band */
    RECT *pRegEnd;            /* End of region */
    INT curNumRects;          /* Number of rectangles in current band */
    INT prevNumRects;         /* Number of rectangles in previous band */
    INT bandtop;               /* top coordinate for current band */

    pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
    pPrevRect = (PRECT)pReg->Buffer + prevStart;
    prevNumRects = curStart - prevStart;

    /*
     * Figure out how many rectangles are in the current band. Have to do
     * this because multiple bands could have been added in REGION_RegionOp
     * at the end when one region has been exhausted.
     */
    pCurRect = (PRECT)pReg->Buffer + curStart;
    bandtop = pCurRect->top;
    for (curNumRects = 0;
	 (pCurRect != pRegEnd) && (pCurRect->top == bandtop);
	 curNumRects++)
    {
		pCurRect++;
    }

    if (pCurRect != pRegEnd)
    {
		/*
		 * If more than one band was added, we have to find the start
		 * of the last band added so the next coalescing job can start
		 * at the right place... (given when multiple bands are added,
		 * this may be pointless -- see above).
		 */
		pRegEnd--;
		while ((pRegEnd-1)->top == pRegEnd->top)
		{
		    pRegEnd--;
		}
		curStart = pRegEnd - (PRECT)pReg->Buffer;
		pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
    }

    if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
		pCurRect -= curNumRects;
		/*
		 * The bands may only be coalesced if the bottom of the previous
		 * matches the top scanline of the current.
		 */
		if (pPrevRect->bottom == pCurRect->top)
		{
		    /*
		     * Make sure the bands have rects in the same places. This
		     * assumes that rects have been added in such a way that they
		     * cover the most area possible. I.e. two rects in a band must
		     * have some horizontal space between them.
		     */
		    do
		    {
				if ((pPrevRect->left != pCurRect->left) ||
				    (pPrevRect->right != pCurRect->right))
				{
				    /*
				     * The bands don't line up so they can't be coalesced.
				     */
				    return (curStart);
				}
				pPrevRect++;
				pCurRect++;
				prevNumRects -= 1;
		    } while (prevNumRects != 0);

		    pReg->rdh.nCount -= curNumRects;
		    pCurRect -= curNumRects;
		    pPrevRect -= curNumRects;

		    /*
		     * The bands may be merged, so set the bottom of each rect
		     * in the previous band to that of the corresponding rect in
		     * the current band.
		     */
		    do
		    {
				pPrevRect->bottom = pCurRect->bottom;
				pPrevRect++;
				pCurRect++;
				curNumRects -= 1;
		    } while (curNumRects != 0);

		    /*
		     * If only one band was added to the region, we have to backup
		     * curStart to the start of the previous band.
		     *
		     * If more than one band was added to the region, copy the
		     * other bands down. The assumption here is that the other bands
		     * came from the same region as the current one and no further
		     * coalescing can be done on them since it's all been done
		     * already... curStart is already in the right place.
		     */
		    if (pCurRect == pRegEnd)
		    {
				curStart = prevStart;
		    }
		    else
		    {
				do
				{
				    *pPrevRect++ = *pCurRect++;
				} while (pCurRect != pRegEnd);
		    }
		}
    }
    return (curStart);
}

/*!
 *      Apply an operation to two regions. Called by REGION_Union,
 *      REGION_Inverse, REGION_Subtract, REGION_Intersect...
 *
 * Results:
 *      None.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -