Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Guide to WIN32 Clipping Regions

0.00/5 (No votes)
9 Apr 2002 1  
Guide to understand the three different types of clipping regions, and how they relate to the Device Context.

Introduction

Clipping is a tool that can be very useful when painting complex user interfaces for any type of computer graphics display. There are two types of clipping in the subject of computer graphics, clipping to improve performance, and clipping for effect. This article will focus on how clipping is implemented in the WIN32 API, specifically within device contexts (DC)s.

While some of the discussion in this tutorial may only be of interest to developers who seek advanced knowledge on the WIN32 clipping regions, the bulk of this guide is set at an intermediate level. Also, to know many of the secrets behind the structure and organization of the clipping regions will allow you to make design decisions that will allow you to more readily exploit these features.

Much of the knowledge that was gained for this article was learned from the book Windows Graphics Programming by Feng Yuan. The example that is presented is also inspired by a demonstration program in that book. The demo program has been developed in the windows SDK because the code is so simple.

Device Context and its Regions

For all intents and purposes, a DC is an array of pixels aligned in a rectangle. When no restriction is imposed, any one of these pixels can be written to. However, the DC has three types of regions, that will restrict access (clip) to these pixels. As each of these DCs are modified, the intersection of the DCs will create the final clipping region that allows paint access to a DC.

System Region

The System Region the base region for the device context. This region can also be referred to as the visible region, since it has the effect of only allowing the visible parts of the window to be displayed. Initially it will encompass the entire DC. The system is usually in charge of defining and maintaining this region, however, it is possible for the application to access this region, and even set the initial System Region for a device context. This region is closely related to the target window that the DC was created for. The System Region is also calculated from a number of different factors. These factors include the following:

  • The target window rectangle or region if it was modified by SetWindowRgn.
  • The window regions for child windows will be removed from the System Region if the CS_CLIPCHILDREN class style is set.
  • The window regions for all of the windows above the target window in the Z-Order will be removed as well.
  • If BeginPaint was used to create the DC, then the update region for the window will be intersected with the remaining System Region.

Clip Region

This region is defined by the application, and is the most common region, in which clipping is accomplished by developers. When a DC is created, the initial Clip region is set to the entire device surface of the DC. This region can be changed, manipulated and even cleared through the life of the DC by the application.

Meta Region

This region is very similar to the Clip Region, however, it is not very well documented in MSDN. The primary purpose of this region is to set a Clip Region for meta files when they are displayed to a drawing surface while allowing the Clip Region to remain intact. This region can also be thought of as a second Clip Region.

More details will be given on possible uses for each of these types of clipping regions after the APIs that manipulate these regions are explained in detail.

System Region Functions

There are only two functions that allow access to the System Region. Both functions are described in full detail, as well as some of the undocumented features of these functions.

GetRandomRgn

The GetRandomRgn function copies the system clipping region of a specified device context to a specific region. You may need to get the newer versions of the windows header files in order to have access to this function, it has just recently been documented in MSDN, but has been exported from GDI32.dll for quite some time. The only value that is documented for the iNum parameters is SYSRGN which is defined as the value 4 in wingdi.h. As you can see from the description below extracted from MSDN, the iNum must be set to SYSRGN. This is simply not true. There are three other undocumented values that are legal to send to this function.

int GetRandomRgn(
  HDC  hdc,    // handle to DC

  HRGN hrgn,   // handle to region

  INT  iNum    // must be SYSRGN

);

Here are the four valid values, and their effect when set into iNum in GetRandomRgn:

  • VALUE = 1: This undocumented value will return the current Clip Region contained in the DC.
  • VALUE = 2: This undocumented value will return the current Meta Region contained in the DC.
  • VALUE = 3: This undocumented value will return the intersection of the Clip Region and Meta Region. Feng Yuan calls this region the Rao region, which is supposedly named after the Microsoft engineer that convinced the development team to cache this intersected region to increase performance. Take this for what it is worth.
  • VALUE = 4, SYSRGN: The only value that is documented and defined for this function. This value returns the System Region that was described earlier.

One more thing to be aware of when a region is retrieved from GetRandomRgn is that on Windows 9x operating systems the region is returned in window coordinates, and on Windows NT machines the region is in screen coordinates. Therefore to use the region in a window on Windows NT machines the region will need to be offset. Here is a piece of code that can be used to translate the region on a Windows NT machine.

POINT pt = {0,0};
::MapWindowPoints(NULL, hWnd, &pt, 1);

::OffsetRgn(hRgn, pt.x, pt.y);

GetDCEx

The GetDCEx function retrieves a handle to a DC for a specified window or for the entire screen. This function allows the developer to specify an initial Clip Region for the newly created DC. However, this statement is a little misconceiving. The actaul region that gets set when a clipping region is specified is the System Region. This is the developer's backdoor into setting the System Region for a DC. However, one the region is set and the DC is created, there is no way for an application to directly manipulate the System Region.

HDC GetDCEx(
  HWND hWnd,      // handle to window

  HRGN hrgnClip,  // handle to clipping region

  DWORD flags     // creation options

);

In order to set the region, one of these two flags must be used to indicate how to use the region:

  • DCX_EXCLUDERGN: The clipping region identified by hrgnClip is excluded from the visible region of the returned DC.
  • DCX_INTERSECTRGN: The clipping region identified by hrgnClip is intersected with the visible region of the returned DC. This would have the effect of reallowing the regions that have already been clipped away for child window clipping and Z-Order clipping to be painted on.

One thing to be aware of when passing a valid region to this function, is that this function assumes ownership of the region. It is very important that this region is not deleted or even used after this function call.

The regions that are stored in a DC are stored in window coordinates on a Windows 9x machine and in screen coordinates on a Windows NT machine. This means that if the region is to be set in GetDCEx on a Windows NT machine, then the region will need to be translated to screen coordinates relative to the window before the call to GetDCEx. Here is a small code sample that demonstrates how to do this:

	POINT pt = {0,0};
	::MapWindowPoints(hWnd, NULL, &pt, 1);

	::OffsetRgn(hRgn, pt.x, pt.y);

Clipping Region Functions

The Clip Region has the richest set of functions to manipulate their data. These functions allow the region to be set directly, modified through boolean intersection, and even translated. A description of each function is given below.

GetClipBox

The GetClipBox function retrieves the dimensions of the tightest bounding rectangle that can be drawn around the current visible area on the device. The visible area is defined by the current Clip Region or clip path, as well as any overlapping windows.

int GetClipBox(
  HDC hdc,      // handle to DC

  LPRECT lprc   // rectangle

);

The dimensions that this function return are in logical coordinates for the current DC. The return value will indicate the current region type that is stored in the Clip Region.

GetClipRgn

The GetClipRgn function retrieves a handle identifying the current application-defined Clip Region for the specified device context. The region that is returned will be in device coordinates, rather than logical coordinates. This differs from the behaviour for GetClipBox. It is highly likely that this function could be implemented in terms of GetRandomRgn by simply passing in a 1 to the iNum parameter.

int GetClipRgn(
  HDC hdc,           // handle to DC

  HRGN hrgn          // handle to region

);

SelectClipRgn

The SelectClipRgn function selects a region as the current Clip Region for the specified device context. This is the simplest way to set the Clip Region of a device context.

int SelectClipRgn(
  HDC hdc,    // handle to DC

  HRGN hrgn   // handle to region

);

The dimensions that this function return are in device coordinates for the current DC. The return value will indicate the current region type that is stored in the Clip Region.

ExtSelectClipRgn

The ExtSelectClipRgn function combines the specified region with the current Clip Region using the specified mode. If you would like more details on how the different modes will affect the current Clip Region, refer to this guide: Guide to WIN32 Regions.

int ExtSelectClipRgn(
  HDC hdc,          // handle to DC

  HRGN hrgn,        // handle to region

  int fnMode        // region-selection mode

);

The dimensions that this function return are in device coordinates for the current DC. The return value will indicate the current region type that is stored in the Clip Region.

IntersectClipRect

The IntersectClipRect function creates a new Clip Region from the intersection of the current Clip Region and the specified rectangle. Unless one of the other clipping functions has been called to modify the initial Clip Region, this function will have not effect as the default Clip Region includes the entire DC.

int IntersectClipRect(
  HDC hdc,         // handle to DC

  int nLeftRect,   // x-coord of upper-left corner

  int nTopRect,    // y-coord of upper-left corner

  int nRightRect,  // x-coord of lower-right corner

  int nBottomRect  // y-coord of lower-right corner

);

ExcludeClipRect

The ExcludeClipRect function creates a new Clip Region that consists of the existing Clip Region minus the specified rectangle.

int ExcludeClipRect(
  HDC hdc,         // handle to DC

  int nLeftRect,   // x-coord of upper-left corner

  int nTopRect,    // y-coord of upper-left corner

  int nRightRect,  // x-coord of lower-right corner

  int nBottomRect  // y-coord of lower-right corner

);

OffsetClipRgn

The OffsetClipRgn function moves the Clip Region of a device context by the specified offsets.

int OffsetClipRgn(
  HDC hdc,       // handle to DC

  int nXOffset,  // offset along x-axis

  int nYOffset   // offset along y-axis

);

SelectClipPath

The SelectClipPath function selects the current path as a Clip Region for a device context, combining the new region with any existing Clip Region using the specified mode.

BOOL SelectClipPath(
  HDC hdc,    // handle to DC

  int iMode   // clipping mode

);

Meta Region Functions

At first glance the set of Meta Region functions may seem a little meager with only two. However, when a Meta Region is set, it will combine the intersection of the current Meta Region, with the current clip region. The Clip Region will then be reset to the entire DC. This in effect allows the Meta Region to use all of the Clip region functions in order to create itself. It is highly likely that this function could be implemented in terms of GetRandomRgn by simply passing in a 2 to the iNum parameter.

It is however, very important that SaveDC is used to save the state of the DC before a meta region is set into the DC. Because when a Meta Region is created, it is intersected with the current Meta Region. Once a Meta Region region is reduced from the default client rectangle, then the region cannot be returned back to its original state except by restoring a previously saved DC context.

GetMetaRgn

The GetMetaRgn function retrieves the current meta region for the specified device context.

int GetMetaRgn(
  HDC hdc,    // handle to DC

  HRGN hrgn   // handle to region

);

SetMetaRgn

The SetMetaRgn function intersects the current Clip Region for the specified device context with the current meta region and saves the combined region as the new meta region for the specified device context. The Clip Region is reset to a null region. The only way to reset the Meta Region to its original state is to return to a previously saved version of the DC with SaveDC.

int SetMetaRgn(
  HDC hdc   // handle to DC

);

Application of the DC Regions

The regions that are a part of the DC are used extensively. Quite often an application will use these regions and not be unaware of this fact. By understanding the regions that are used, and what these regions accomplish, a developer can possibly design their system around these features in order to create a more efficient program. This fact is especially true when an application or control is implemented that does not follow the normal design for WIN32 development.

BeginPaint

This is probably the most common use of the regions that are involved the DC. Internally BeginPaint makes a call to GetDCEx in order to create the DC that finally gets used. The current update region for the target window is used as the clipping region in GetDCEx. This final result is the System Region is equivalent to the Update Region of the window for the paint DC. When the application attempts to paint on the paint DC, only the regions that have been invalidated will be repainted.

At this point the application could call GetRandomRgn in order to get the region that needs to be repainted, and factor out all of the unnecessary painting increasing the efficiency of the paint routine. Even if the application sends the entire window to be repainted upon each paint message, the display ultimately experiences less flicker because of the automatic clipping that is experienced by the System Region. In order to see a demonstration of the flicker that would occur with out this feature, make a call to InvalidateRect before BeginPaint in your paint handler.

InvalidateRect(hWnd, NULL, TRUE);
This will have the effect of invalidating the entire target window, and eliminating any benefit that System Region provides.

Clipping for Effect

Use the Clip Region to create a mask that only allows a special portion of the DC to be painted on. This is probably what is most commonly thought of when the term clipping is mentioned in WIN32 development.

Metafiles

Metafiles are a way for an application or an artist to store a set of vector drawing commands in a file in order to draw them on a surface at a later time. Metafiles are great in the fact that they are vector based which means that they will scale well to just about any size that they should be displayed at. The drawing dimensions of a metafile are only restricted to the resolution of the values used in window GDI.

If an application uses metafiles to paint a portion of a display, it may be necessary to setup a clipping region to restrict the areas that rogue metafiles can paint to. That is where the Meta Region is mainly used for. The application can set up a boundary in the Meta Region that cannot be painted to, that may be different than the Clip Region. This is in fact the original intention of the Meta Region.

Libraries

One other possible use for the Meta Region is in imported or exported library code that paints to a DC. If a library function is imported, and this function restricts its painting by use of the Clip Region, it would make it difficult for the host application to further clip the drawing especially of the library function does not incorporate the current Clip Region into the new Clip Region that it creates. The Meta Region would nicely fix this problem.

On the other hand, if drawing code is written to be exported in a library, and the Clip Region is a concern of the developer, then the Meta Region could be used by the library in order to set the proper clipping area, and allow the user of the library to gain further clipping rights.

Demonstration

The demonstration program that is provided has been inspired by a demo program in the book Windows Graphics Programming by Feng Yuan. Each of the three regions of the DC will be demonstrated separately.

This application is written for the Windows SDK. Because of the use of the GetRandomRgn function, the newest header files should be used. This function was only recently exposed in the header files. Just in case, I have included a copy of wingdi.h that contains the definition of GetRandomRgn for those developers with outdated header files. I would only recommend using this file to build the application if you do not currently have the most recent header files. If you want to develop an application using this function, I would download the SDK with the most recent header files.

This application will allow the user to separately configure each of the three regions that are located in the DC. Here is a description of how each of the three regions are presented in the application.

  • System Region: This region is represented by a red border around the boundary of the region. FrameRgn will be used to paint this boundary. The System Region is the only region that the application allows the user to manually set.
  • Clip Region: This region will be represented by vertical dark purple lines. When this region is activated, it will automatically be calculated to be the ellipse that fits vertically between the top and bottom client boundaries, and 2/3 of the width of the window.
  • Meta Region: This region will be represented by horizontal blue lines. When this region is activated, it will automatically be calculated to be the ellipse that fits horizontally between the left and right client boundaries, and 2/3 of the height of the window.
  • Intersection: The intersection of all three regions will always be active and represented by a pale pink colored fill. This represents the region that would be available to the application to paint on if these three regions were set as illustrated.

Here is an example of the display with all three regions activated:
Sample Image

There are four menu settings that can be checked in order to change the display. Listed below are the directions to each of these five settings, and any code that may need extra explanation in order to make the feature work.

  • Default System Region: The System Region that is calculated by Windows will be displayed. When the entire window is refreshed, then the entire client area will be shown as the System Region. However when only a small portion of the window is updated, the System Region will be set to the update region of the window.

    The System Region will be extracted from the DC with this call:

    ::GetRandomRgn(hdc, hSystemRgn, SYSRGN /*4*/);
    	
  • Manual System Region: The System Region can be set by the user tracing a path of the desired System Region. The System Region will be set into the DC with this call:

    //C: Create a region that is the inverse of the User region.
    
    HRGN hRgnExclude = ::CreateRectRgnIndirect(&rClient);
    ::CombineRgn(hRgnExclude, hRgnExclude, g_hUserRgn, RGN_DIFF);
    
    ...
    
    hdc = ::GetDCEx(hWnd, hRgnExclude, DCX_CACHE | DCX_EXCLUDERGN);
    
    //C: Since BeginPaint was not used to create the DC, WM_ERASEBKGND
    
    //   has to be generated manually.
    
    ::SendMessage(hWnd, WM_ERASEBKGND, (WPARAM)hdc, NULL);
    
    //C: Validate the update region for this window to prevent 
    
    //   other calls to WM_PAINT.
    
    ::ValidateRect(hWnd, NULL);	
    Notice the extra code that is used to create the DC. The message for WM_ERASEBKGND and the call to ValidateRect This is because GetDCEx is sued to create the DC rather than BeginPaint. These actions are normally performed inside of BeginPaint.
  • Clip Region: This will activate or deactivate the Clip Region.

  • Meta Region: This will activate or deactivate the Meta Region.

The demonstration program is very simple, however it does show that three distinct regions do exist inside of the DC, and how they determine the final painting surface after all of the clipping has been determined.

Conclusion

Clipping is a technique that can often be ignored. However it can be very beneficial during the right circumstances. WIN32 provides three distinct regions in its DC that all contribute to the final outcome when clipping is applied. Some of the regions require extra effort, like the Clip Region and the Meta Region, however, other regions like the System Region are added as a extra optimization with no extra work on the developers part.

The information that was provided in this guide is probably more than you will ever need to know about windows clipping regions. This knowledge will however allow you to design your program around these features and possibly take advantage of them for your special programming project in the future.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here