Exemplo n.º 1
0
VOID FASTCALL
co_VIS_WindowLayoutChanged(
   PWND Wnd,
   HRGN NewlyExposed)
{
   HRGN Temp;
   PWND Parent;
   USER_REFERENCE_ENTRY Ref;

   ASSERT_REFS_CO(Wnd);

   Parent = Wnd->spwndParent;
   if(Parent)
   {
      Temp = IntSysCreateRectRgn(0, 0, 0, 0);

      NtGdiCombineRgn(Temp, NewlyExposed, NULL, RGN_COPY);
      NtGdiOffsetRgn(Temp,
                     Wnd->rcWindow.left - Parent->rcClient.left,
                     Wnd->rcWindow.top - Parent->rcClient.top);

      UserRefObjectCo(Parent, &Ref);
      co_UserRedrawWindow(Parent, NULL, Temp,
                          RDW_FRAME | RDW_ERASE | RDW_INVALIDATE |
                          RDW_ALLCHILDREN);
      UserDerefObjectCo(Parent);

      GreDeleteObject(Temp);
   }
}
Exemplo n.º 2
0
int FASTCALL GdiExtSelectClipRgn(PDC dc,
                                 HRGN hrgn,
                                 int fnMode)
{
  //  dc->fs &= ~DC_FLAG_DIRTY_RAO;

  if (!hrgn)
  {
    if (fnMode == RGN_COPY)
    {
      if (dc->rosdc.hClipRgn != NULL)
      {
        GreDeleteObject(dc->rosdc.hClipRgn);
        dc->rosdc.hClipRgn = NULL;
      }
    }
    else
    {
      EngSetLastError(ERROR_INVALID_PARAMETER);
      return ERROR;
    }
  }
  else
  {
    if (!dc->rosdc.hClipRgn)
    {
      RECTL rect;
      if(dc->prgnVis)
      {
		REGION_GetRgnBox(dc->prgnVis, &rect);
        dc->rosdc.hClipRgn = IntSysCreateRectRgnIndirect(&rect);
      }
      else
      {
        dc->rosdc.hClipRgn = IntSysCreateRectRgn(0, 0, 0, 0);
      }
    }
    if(fnMode == RGN_COPY)
    {
      NtGdiCombineRgn(dc->rosdc.hClipRgn, hrgn, 0, fnMode);
    }
    else
      NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, hrgn, fnMode);
  }

  return CLIPPING_UpdateGCRegion(dc);
}
Exemplo n.º 3
0
INT
Test_NtGdiCombineRgn(PTESTINFO pti)
{
	HRGN hRgnDest, hRgn1, hRgn2;
// test what params are accepted for what operations
// 0? invalid? are params maybe ignored in some cases?
// LastError

	/* Preparation */
	hRgnDest = CreateRectRgn(0,0,1,1);
	hRgn1 = CreateRectRgn(1,1,4,4);
	hRgn2 = CreateRectRgn(2,2,6,3);

	/* RGN_AND = 1, RGN_OR = 2, RGN_XOR = 3, RGN_DIFF = 4, RGN_COPY = 5 */

	TEST(NtGdiCombineRgn(hRgnDest, hRgn1, hRgn2, 0) == ERROR);
	TEST(NtGdiCombineRgn(hRgnDest, hRgn1, hRgn2, 6) == ERROR);

	SetLastError(ERROR_SUCCESS);
	TEST(NtGdiCombineRgn(hRgnDest, 0, 0, RGN_AND) == ERROR);
	TEST(GetLastError() == ERROR_INVALID_HANDLE);
	SetLastError(ERROR_SUCCESS);
	TEST(NtGdiCombineRgn(hRgnDest, hRgn1, 0, RGN_AND) == ERROR);
	TEST(GetLastError() == ERROR_INVALID_HANDLE);
	SetLastError(ERROR_SUCCESS);
	TEST(NtGdiCombineRgn(hRgnDest, 0, hRgn1, RGN_AND) == ERROR);
	TEST(GetLastError() == ERROR_INVALID_HANDLE);
	SetLastError(ERROR_SUCCESS);
	TEST(NtGdiCombineRgn(0, hRgn1, hRgn2, RGN_AND) == ERROR);
	TEST(GetLastError() == ERROR_INVALID_HANDLE);

	/* Create intersection */
	TEST(NtGdiCombineRgn(hRgnDest, hRgn1, hRgn2, RGN_AND) == SIMPLEREGION);
	SetRectRgn(hRgn1, 2, 2, 4, 3);
	TEST(NtGdiCombineRgn(hRgnDest, hRgnDest, hRgn1, RGN_XOR) == NULLREGION);

	/* Create intersection with itself */
	SetRectRgn(hRgnDest, 2, 2, 4, 3);
	TEST(NtGdiCombineRgn(hRgnDest, hRgnDest, hRgnDest, RGN_AND) == SIMPLEREGION);
	SetRectRgn(hRgn1, 2, 2, 4, 3);
	TEST(NtGdiCombineRgn(hRgnDest, hRgnDest, hRgn1, RGN_XOR) == NULLREGION);


	/* What if 2 regions are the same */

	return APISTATUS_NORMAL;
}
Exemplo n.º 4
0
int APIENTRY NtGdiIntersectClipRect(HDC  hDC,
                           int  LeftRect,
                           int  TopRect,
                           int  RightRect,
                           int  BottomRect)
{
   INT Result;
   RECTL Rect;
   HRGN NewRgn;
   PDC dc = DC_LockDc(hDC);

   DPRINT("NtGdiIntersectClipRect(%x, %d,%d-%d,%d)\n",
      hDC, LeftRect, TopRect, RightRect, BottomRect);

   if (!dc)
   {
      EngSetLastError(ERROR_INVALID_HANDLE);
      return ERROR;
   }

   Rect.left = LeftRect;
   Rect.top = TopRect;
   Rect.right = RightRect;
   Rect.bottom = BottomRect;

   IntLPtoDP(dc, (LPPOINT)&Rect, 2);

   NewRgn = IntSysCreateRectRgnIndirect(&Rect);
   if (!NewRgn)
   {
      Result = ERROR;
   }
   else if (!dc->rosdc.hClipRgn)
   {
      dc->rosdc.hClipRgn = NewRgn;
      Result = SIMPLEREGION;
   }
   else
   {
      Result = NtGdiCombineRgn(dc->rosdc.hClipRgn, dc->rosdc.hClipRgn, NewRgn, RGN_AND);
      GreDeleteObject(NewRgn);
   }
   if (Result != ERROR)
      CLIPPING_UpdateGCRegion(dc);

   DC_UnlockDc(dc);

   return Result;
}
Exemplo n.º 5
0
/*
 * @implemented
 */
INT
WINAPI
CombineRgn(
    _In_ HRGN hrgnDest,
    _In_ HRGN hrgnSrc1,
    _In_ HRGN hrgnSrc2,
    _In_ INT  iCombineMode)
{
    PRGN_ATTR prngattrDest = NULL;
    PRGN_ATTR prngattrSrc1 = NULL;
    PRGN_ATTR prngattrSrc2 = NULL;
    RECT rcTemp;

    /* Get the region attribute for dest and source 1 */
    prngattrDest = GdiGetRgnAttr(hrgnDest);
    prngattrSrc1 = GdiGetRgnAttr(hrgnSrc1);

    /* If that failed or if the source 1 region is complex, go to win32k */
    if ((prngattrDest == NULL) || (prngattrSrc1 == NULL) ||
        (prngattrSrc1->iComplexity > SIMPLEREGION))
    {
        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
    }

    /* Handle RGN_COPY first, it needs only hrgnSrc1 */
    if (iCombineMode == RGN_COPY)
    {
        /* Check if the source region is a NULLREGION */
        if (prngattrSrc1->iComplexity == NULLREGION)
        {
            /* The dest region is a NULLREGION, too */
            return IntSetNullRgn(prngattrDest);
        }

        /* We already know that the source region cannot be complex, so
           create a rect region from the bounds of the source rect */
        return IntSetRectRgn(prngattrDest,
                             prngattrSrc1->Rect.left,
                             prngattrSrc1->Rect.top,
                             prngattrSrc1->Rect.right,
                             prngattrSrc1->Rect.bottom);
    }

    /* For all other operations we need hrgnSrc2 */
    prngattrSrc2 = GdiGetRgnAttr(hrgnSrc2);

    /* If we got no attribute or the region is complex, go to win32k */
    if ((prngattrSrc2 == NULL) || (prngattrSrc2->iComplexity > SIMPLEREGION))
    {
        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
    }

    /* Handle RGN_AND */
    if (iCombineMode == RGN_AND)
    {
        /* Check if either of the regions is a NULLREGION */
        if ((prngattrSrc1->iComplexity == NULLREGION) ||
            (prngattrSrc2->iComplexity == NULLREGION))
        {
            /* Result is also a NULLREGION */
            return IntSetNullRgn(prngattrDest);
        }

        /* Get the intersection of the 2 rects */
        if (!IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
        {
            /* The rects do not intersect, result is a NULLREGION */
            return IntSetNullRgn(prngattrDest);
        }

        /* Use the intersection of the rects */
        return IntSetRectRgn(prngattrDest,
                             rcTemp.left,
                             rcTemp.top,
                             rcTemp.right,
                             rcTemp.bottom);
    }

    /* Handle RGN_DIFF */
    if (iCombineMode == RGN_DIFF)
    {
        /* Check if source 1 is a NULLREGION */
        if (prngattrSrc1->iComplexity == NULLREGION)
        {
            /* The result is a NULLREGION as well */
            return IntSetNullRgn(prngattrDest);
        }

        /* Get the intersection of the 2 rects */
        if ((prngattrSrc2->iComplexity == NULLREGION) ||
            !IntersectRect(&rcTemp, &prngattrSrc1->Rect, &prngattrSrc2->Rect))
        {
            /* The rects do not intersect, dest equals source 1 */
            return IntSetRectRgn(prngattrDest,
                                 prngattrSrc1->Rect.left,
                                 prngattrSrc1->Rect.top,
                                 prngattrSrc1->Rect.right,
                                 prngattrSrc1->Rect.bottom);
        }

        /* We need to check is whether we can subtract the rects. For that
           we call SubtractRect, which will give us the bounding box of the
           subtraction. The function returns FALSE if the resulting rect is
           empty */
        if (!SubtractRect(&rcTemp, &prngattrSrc1->Rect, &rcTemp))
        {
            /* The result is a NULLREGION */
            return IntSetNullRgn(prngattrDest);
        }

        /* Now check if the result of SubtractRect matches the source 1 rect.
           Since we already know that the rects intersect, the result can
           only match the source 1 rect, if it could not be "cut" on either
           side, but the overlapping was on a corner, so the new bounding box
           equals the previous rect */
        if (!EqualRect(&rcTemp, &prngattrSrc1->Rect))
        {
            /* We got a properly subtracted rect, so use it. */
            return IntSetRectRgn(prngattrDest,
                                 rcTemp.left,
                                 rcTemp.top,
                                 rcTemp.right,
                                 rcTemp.bottom);
        }

        /* The result would be a complex region, go to win32k */
        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
    }

    /* Handle OR and XOR */
    if ((iCombineMode == RGN_OR) || (iCombineMode == RGN_XOR))
    {
        /* Check if source 1 is a NULLREGION */
        if (prngattrSrc1->iComplexity == NULLREGION)
        {
            /* Check if source 2 is also a NULLREGION */
            if (prngattrSrc2->iComplexity == NULLREGION)
            {
                /* Both are NULLREGIONs, result is also a NULLREGION */
                return IntSetNullRgn(prngattrDest);
            }

            /* The result is equal to source 2 */
            return IntSetRectRgn(prngattrDest,
                                 prngattrSrc2->Rect.left,
                                 prngattrSrc2->Rect.top,
                                 prngattrSrc2->Rect.right,
                                 prngattrSrc2->Rect.bottom );
        }

        /* Check if only source 2 is a NULLREGION */
        if (prngattrSrc2->iComplexity == NULLREGION)
        {
            /* The result is equal to source 1 */
            return IntSetRectRgn(prngattrDest,
                                 prngattrSrc1->Rect.left,
                                 prngattrSrc1->Rect.top,
                                 prngattrSrc1->Rect.right,
                                 prngattrSrc1->Rect.bottom);
        }

        /* Do the rects have the same x extent */
        if ((prngattrSrc1->Rect.left == prngattrSrc2->Rect.left) &&
            (prngattrSrc1->Rect.right == prngattrSrc2->Rect.right))
        {
            /* Do the rects also have the same y extent */
            if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
                (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
            {
                /* Rects are equal, if this is RGN_OR, the result is source 1 */
                if (iCombineMode == RGN_OR)
                {
                    /* The result is equal to source 1 */
                    return IntSetRectRgn(prngattrDest,
                                         prngattrSrc1->Rect.left,
                                         prngattrSrc1->Rect.top,
                                         prngattrSrc1->Rect.right,
                                         prngattrSrc1->Rect.bottom );
                }
                else
                {
                    /* XORing with itself yields an empty region */
                    return IntSetNullRgn(prngattrDest);
                }
            }

            /* Check if the rects are disjoint */
            if ((prngattrSrc2->Rect.bottom < prngattrSrc1->Rect.top) ||
                (prngattrSrc2->Rect.top > prngattrSrc1->Rect.bottom))
            {
                /* The result would be a complex region, go to win32k */
                return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
            }

            /* Check if this is OR */
            if (iCombineMode == RGN_OR)
            {
                /* Use the maximum extent of both rects combined */
                return IntSetRectRgn(prngattrDest,
                                     prngattrSrc1->Rect.left,
                                     min(prngattrSrc1->Rect.top, prngattrSrc2->Rect.top),
                                     prngattrSrc1->Rect.right,
                                     max(prngattrSrc1->Rect.bottom, prngattrSrc2->Rect.bottom));
            }

            /* Check if the rects are adjacent */
            if (prngattrSrc2->Rect.bottom == prngattrSrc1->Rect.top)
            {
                /* The result is the combined rects */
                return IntSetRectRgn(prngattrDest,
                                     prngattrSrc1->Rect.left,
                                     prngattrSrc2->Rect.top,
                                     prngattrSrc1->Rect.right,
                                     prngattrSrc1->Rect.bottom );
            }
            else if (prngattrSrc2->Rect.top == prngattrSrc1->Rect.bottom)
            {
                /* The result is the combined rects */
                return IntSetRectRgn(prngattrDest,
                                     prngattrSrc1->Rect.left,
                                     prngattrSrc1->Rect.top,
                                     prngattrSrc1->Rect.right,
                                     prngattrSrc2->Rect.bottom );
            }

            /* When we are here, this is RGN_XOR and the rects overlap */
            return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
        }

        /* Do the rects have the same y extent */
        if ((prngattrSrc1->Rect.top == prngattrSrc2->Rect.top) &&
            (prngattrSrc1->Rect.bottom == prngattrSrc2->Rect.bottom))
        {
            /* Check if the rects are disjoint */
            if ((prngattrSrc2->Rect.right < prngattrSrc1->Rect.left) ||
                (prngattrSrc2->Rect.left > prngattrSrc1->Rect.right))
            {
                /* The result would be a complex region, go to win32k */
                return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
            }

            /* Check if this is OR */
            if (iCombineMode == RGN_OR)
            {
                /* Use the maximum extent of both rects combined */
                return IntSetRectRgn(prngattrDest,
                                     min(prngattrSrc1->Rect.left, prngattrSrc2->Rect.left),
                                     prngattrSrc1->Rect.top,
                                     max(prngattrSrc1->Rect.right, prngattrSrc2->Rect.right),
                                     prngattrSrc1->Rect.bottom);
            }

            /* Check if the rects are adjacent */
            if (prngattrSrc2->Rect.right == prngattrSrc1->Rect.left)
            {
                /* The result is the combined rects */
                return IntSetRectRgn(prngattrDest,
                                     prngattrSrc2->Rect.left,
                                     prngattrSrc1->Rect.top,
                                     prngattrSrc1->Rect.right,
                                     prngattrSrc1->Rect.bottom );
            }
            else if (prngattrSrc2->Rect.left == prngattrSrc1->Rect.right)
            {
                /* The result is the combined rects */
                return IntSetRectRgn(prngattrDest,
                                     prngattrSrc1->Rect.left,
                                     prngattrSrc1->Rect.top,
                                     prngattrSrc2->Rect.right,
                                     prngattrSrc1->Rect.bottom );
            }

            /* When we are here, this is RGN_XOR and the rects overlap */
            return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
        }

        /* Last case: RGN_OR and one rect is completely within the other */
        if (iCombineMode == RGN_OR)
        {
            /* Check if rect 1 can contain rect 2 */
            if (prngattrSrc1->Rect.left <= prngattrSrc2->Rect.left)
            {
                /* rect 1 might be the outer one, check of that is true */
                if ((prngattrSrc1->Rect.right >= prngattrSrc2->Rect.right) &&
                    (prngattrSrc1->Rect.top <= prngattrSrc2->Rect.top) &&
                    (prngattrSrc1->Rect.bottom >= prngattrSrc2->Rect.bottom))
                {
                    /* Rect 1 contains rect 2, use it */
                    return IntSetRectRgn(prngattrDest,
                                         prngattrSrc1->Rect.left,
                                         prngattrSrc1->Rect.top,
                                         prngattrSrc1->Rect.right,
                                         prngattrSrc1->Rect.bottom );
                }
            }
            else
            {
                /* rect 2 might be the outer one, check of that is true */
                if ((prngattrSrc2->Rect.right >= prngattrSrc1->Rect.right) &&
                    (prngattrSrc2->Rect.top <= prngattrSrc1->Rect.top) &&
                    (prngattrSrc2->Rect.bottom >= prngattrSrc1->Rect.bottom))
                {
                    /* Rect 2 contains rect 1, use it */
                    return IntSetRectRgn(prngattrDest,
                                         prngattrSrc2->Rect.left,
                                         prngattrSrc2->Rect.top,
                                         prngattrSrc2->Rect.right,
                                         prngattrSrc2->Rect.bottom );
                }
            }
        }

        /* We couldn't handle the operation, go to win32k */
        return NtGdiCombineRgn(hrgnDest, hrgnSrc1, hrgnSrc2, iCombineMode);
    }

    DPRINT1("Invalid iCombineMode %d\n", iCombineMode);
    SetLastError(ERROR_INVALID_PARAMETER);
    return ERROR;
}
Exemplo n.º 6
0
HRGN FASTCALL
VIS_ComputeVisibleRegion(
   PWND Wnd,
   BOOLEAN ClientArea,
   BOOLEAN ClipChildren,
   BOOLEAN ClipSiblings)
{
   HRGN VisRgn, ClipRgn;
   PWND PreviousWindow, CurrentWindow, CurrentSibling;

   if (!Wnd || !(Wnd->style & WS_VISIBLE))
   {
      return NULL;
   }

   VisRgn = NULL;

   if (ClientArea)
   {
      VisRgn = IntSysCreateRectRgnIndirect(&Wnd->rcClient);
   }
   else
   {
      VisRgn = IntSysCreateRectRgnIndirect(&Wnd->rcWindow);
   }

   /*
    * Walk through all parent windows and for each clip the visble region
    * to the parent's client area and exclude all siblings that are over
    * our window.
    */

   PreviousWindow = Wnd;
   CurrentWindow = Wnd->spwndParent;
   while (CurrentWindow)
   {
      if ( CurrentWindow->state2 & WNDS2_INDESTROY ||
           CurrentWindow->state & WNDS_DESTROYED )
      {
         ERR("ATM the Current Window or Parent is dead!\n");
         if (VisRgn) GreDeleteObject(VisRgn);
         return NULL;
      }

      if (!(CurrentWindow->style & WS_VISIBLE))
      {
         if (VisRgn) GreDeleteObject(VisRgn);
         return NULL;
      }

      ClipRgn = IntSysCreateRectRgnIndirect(&CurrentWindow->rcClient);
      NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_AND);
      GreDeleteObject(ClipRgn);

      if ((PreviousWindow->style & WS_CLIPSIBLINGS) ||
          (PreviousWindow == Wnd && ClipSiblings))
      {
         CurrentSibling = CurrentWindow->spwndChild;
         while ( CurrentSibling != NULL &&
                 CurrentSibling != PreviousWindow )
         {
            if ((CurrentSibling->style & WS_VISIBLE) &&
                !(CurrentSibling->ExStyle & WS_EX_TRANSPARENT))
            {
               ClipRgn = IntSysCreateRectRgnIndirect(&CurrentSibling->rcWindow);
               /* Combine it with the window region if available */
               if (CurrentSibling->hrgnClip && !(CurrentSibling->style & WS_MINIMIZE))
               {
                  NtGdiOffsetRgn(ClipRgn, -CurrentSibling->rcWindow.left, -CurrentSibling->rcWindow.top);
                  NtGdiCombineRgn(ClipRgn, ClipRgn, CurrentSibling->hrgnClip, RGN_AND);
                  NtGdiOffsetRgn(ClipRgn, CurrentSibling->rcWindow.left, CurrentSibling->rcWindow.top);
               }
               NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
               GreDeleteObject(ClipRgn);
            }
            CurrentSibling = CurrentSibling->spwndNext;
         }
      }

      PreviousWindow = CurrentWindow;
      CurrentWindow = CurrentWindow->spwndParent;
   }

   if (ClipChildren)
   {
      CurrentWindow = Wnd->spwndChild;
      while (CurrentWindow)
      {
         if ((CurrentWindow->style & WS_VISIBLE) &&
             !(CurrentWindow->ExStyle & WS_EX_TRANSPARENT))
         {
            ClipRgn = IntSysCreateRectRgnIndirect(&CurrentWindow->rcWindow);
            /* Combine it with the window region if available */
            if (CurrentWindow->hrgnClip && !(CurrentWindow->style & WS_MINIMIZE))
            {
               NtGdiOffsetRgn(ClipRgn, -CurrentWindow->rcWindow.left, -CurrentWindow->rcWindow.top);
               NtGdiCombineRgn(ClipRgn, ClipRgn, CurrentWindow->hrgnClip, RGN_AND);
               NtGdiOffsetRgn(ClipRgn, CurrentWindow->rcWindow.left, CurrentWindow->rcWindow.top);
            }
            NtGdiCombineRgn(VisRgn, VisRgn, ClipRgn, RGN_DIFF);
            GreDeleteObject(ClipRgn);
         }
         CurrentWindow = CurrentWindow->spwndNext;
      }
   }

   if (Wnd->hrgnClip && !(Wnd->style & WS_MINIMIZE))
   {
      NtGdiOffsetRgn(VisRgn, -Wnd->rcWindow.left, -Wnd->rcWindow.top);
      NtGdiCombineRgn(VisRgn, VisRgn, Wnd->hrgnClip, RGN_AND);
      NtGdiOffsetRgn(VisRgn, Wnd->rcWindow.left, Wnd->rcWindow.top);
   }

   return VisRgn;
}
Exemplo n.º 7
0
/* See wine, msdn, osr and  Feng Yuan - Windows Graphics Programming Win32 Gdi And Directdraw

   1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!

   The intersection of the clip with the meta region is not Rao it's API!
   Go back and read 7.2 Clipping pages 418-19:
   Rao = API & Vis:
   1) The Rao region is the intersection of the API region and the system region,
      named after the Microsoft engineer who initially proposed it.
   2) The Rao region can be calculated from the API region and the system region.

   API:
      API region is the intersection of the meta region and the clipping region,
      clearly named after the fact that it is controlled by GDI API calls.
*/
INT
APIENTRY
NtGdiGetRandomRgn(
    HDC hdc,
    HRGN hrgnDest,
    INT iCode)
{
    INT ret = 0;
    PDC pdc;
    HRGN hrgnSrc = NULL;
    POINTL ptlOrg;

    pdc = DC_LockDc(hdc);
    if (!pdc)
    {
        EngSetLastError(ERROR_INVALID_PARAMETER);
        return -1;
    }

    switch (iCode)
    {
        case CLIPRGN:
            hrgnSrc = pdc->rosdc.hClipRgn;
//            if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
            break;
        case METARGN:
            if (pdc->dclevel.prgnMeta)
                hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
            break;
        case APIRGN:
            if (pdc->prgnAPI) hrgnSrc = pdc->prgnAPI->BaseObject.hHmgr;
//            else if (pdc->dclevel.prgnClip) hrgnSrc = pdc->dclevel.prgnClip->BaseObject.hHmgr;
            else if (pdc->rosdc.hClipRgn) hrgnSrc = pdc->rosdc.hClipRgn;
            else if (pdc->dclevel.prgnMeta) hrgnSrc = pdc->dclevel.prgnMeta->BaseObject.hHmgr;
            break;
        case SYSRGN:
            if (pdc->prgnVis)
            {
                PREGION prgnDest = REGION_LockRgn(hrgnDest);
                ret = IntGdiCombineRgn(prgnDest, pdc->prgnVis, 0, RGN_COPY) == ERROR ? -1 : 1;
                REGION_UnlockRgn(prgnDest);
            }
            break;
        default:
            hrgnSrc = NULL;
    }

    if (hrgnSrc)
    {
        ret = NtGdiCombineRgn(hrgnDest, hrgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
    }

    if (iCode == SYSRGN)
    {
        ptlOrg = pdc->ptlDCOrig;
        NtGdiOffsetRgn(hrgnDest, ptlOrg.x, ptlOrg.y );
    }

    DC_UnlockDc(pdc);

    return ret;
}