The primary job of any graphics context object is to maintain information about the current state of the drawing environment. In Quartz, the graphics context object is associated with a window, bitmap, PDF file, or other output device and maintains information for that device. The same is true for a Cocoa graphics context, but because Cocoa drawing is view-based, some additional changes are made to the drawing environment before your view’s drawRect: method is called.
By the time your view’s drawRect: method is called, Cocoa has made sure that any drawing calls you make stay within the confines of your view. It saves the graphics state to simplify the process of undoing its changes later. It adds an appropriate transform to the current transformation matrix to place the drawing origin at the origin of your view. It also sets the clipping region to your view's visible boundaries, preventing any rendered content from straying into other views. Your view is effectively the star of the show, at least until another view’s drawRect: method is called.
While the current context is focused on your view, you can draw paths, images, text, or any other content you want. You can also change the attributes of the current drawing environment to achieve the appearance you want for your content. Eventually, the content you draw is sent to the Quartz Compositor, where it is combined with the content from other views in the window and flushed to the screen or output device.
After your drawRect: method returns, Cocoa goes through the process of resetting the drawing environment for the next view. It reverts any changes you made to the drawing environment and sets up the coordinate transform and clipping region for the next view, giving it its own pristine environment in which to work. This process then repeats itself during each update cycle in your application.
The Current Context
Graphics State Information
Screen Canvases and Print Canvases
Graphics Contexts and Quartz
Each thread in a Cocoa application has its own graphics context object for a given window. You can access this object from your code using the currentContext method of NSGraphicsContext, as shown in the following example:
NSGraphicsContext* aContext = [NSGraphicsContext currentContext]; |
The currentContext method always returns the Cocoa graphics context object that is appropriate for the current drawing environment. This object keeps track of the current graphics state, lets you save and restore graphics state information, and lets you modify many graphics state attributes. The changes you make to the graphics state affect all subsequent drawing calls. If you change an attribute more than once, only the most recent setting is used.
To save the current graphics state, you use the saveGraphicsState method of NSGraphicsContext. This method essentially pushes a copy of the current state onto a stack, leaving you free to make changes to the current state. When you want to revert back to the previous state, you simply call the restoreGraphicsState method to pop the current graphics state (including all changes since the last save) off of the stack and restore the previous state.
If you plan to change the current graphics state significantly, it is a good idea to save the current state before making your changes. Modifying one or two attributes usually may not merit saving the graphics state, since you can reset or change those individual attributes easily. However, if you are changing more than one or two attributes, it is usually easier to save and restore the entire graphics state. You can call the saveGraphicsState method as often as needed in your code to save snapshots of the current graphics state, but you must be sure to balance each call with a matching call to restoreGraphicsState.
Note: The saveGraphicsState and restoreGraphicsState methods are available both as class methods and as instance methods. The class method versions simply save and restore the graphics state of the current context. The instance methods let you save the state of a specific context object, although in most cases this should be the current context.
The following example shows a simple drawRect: method that iterates over an array of developer-defined objects, each of which is drawn with a different set of attributes. The graphics state is saved and restored during each loop iteration, ensuring that each object starts from the same graphics state.
- (void)drawRect:(NSRect)rect |
{ |
NSGraphicsContext* theContext = [NSGraphicsContext currentContext]; |
int i; |
int numObjects = [myObjectArray count]; |
// Iterate over an array of objects |
// Set the attributes for each before drawing |
for (i = 0; i < numObjects; i++) |
{ |
[theContext saveGraphicsState]; |
// Set the drawing attributes |
// Draw the object |
[theContext restoreGraphicsState]; |
} |
} |
Warning:
When saving and restoring the graphics state, you must balance all calls to saveGraphicsState with a corresponding call to restoreGraphicsState. Failure to do so can result in unexpected changes to the appearance of any windows that use that view.
Each Cocoa graphics context object maintains information about the current state of the drawing environment. This information ranges from the global rendering settings to the attributes used to render the current path and is the same state information saved by Quartz. Whenever you save the current graphics state, you save a copy of the settings listed in Table 2-1.
Attribute |
Description |
|---|---|
Maps points in the view’s coordinate system to points in the destination device's coordinate system. Cocoa modifies the CTM before calling your view’s |
|
Specifies the area of the canvas that can be painted by drawing calls. Cocoa modifies the clipping region to the visible area of your view before calling its |
|
Specifies the width of paths. The default line width is |
|
Specifies how two connected lines are joined together. The default join style is |
|
Specifies the appearance of an open end point on a path. The default line cap style is |
|
Defines a broken pattern for lines, including the initial phase for the style. There is no default dash style, resulting in solid lines. You modify dash styles for a path using an |
|
Determines when lines should be joined with a bevel instead of a miter. Applies only when the line join style is set to |
|
Specifies the accuracy with which curves are rendered. (It is also the maximum error tolerance, measured in pixels.) Smaller numbers result in smoother curves at the expense of more calculations. The interpretation of this value may vary slightly on different rendering devices. The default value is |
|
Specifies the color used for rendering paths. This color applies only to the path line itself, not the area the path encompasses. You can specify colors using any of the system-supported color spaces. This value includes alpha information. Color information is managed by the |
|
Specifies the color used to fill the area enclosed by a path. You can specify colors using any of the system-supported color spaces. This value includes alpha information. Color information is managed by the |
|
Specifies the shadow attributes to apply to rendered content. You set shadows using the | |
Specifies the technique used to map in-gamut colors to the gamut of the current color space. Cocoa does not support setting this attribute directly. Instead, you must use Quartz. For more information, see “Mapping Physical Colors to a Color Space.” |
|
Specifies the font to use when drawing text. You modify font information using the |
|
Specifies the font size to use when drawing text. You modify font information using the |
|
Specifies the character spacing to use when drawing text. (This attribute is supported only indirectly by Cocoa.) For more information on drawing text, see “Text Attributes.” |
|
Specifies how to render the text. (This attribute is supported only indirectly by Cocoa.) For more information on drawing text, see “Text Attributes.” |
|
Specifies the process used to interpolate images during rendering. You use the | |
Specifies the process used to composite source and destination material together. (The compositing operations supported by Cocoa are related to the Quartz blend modes but differ in their usage and behavior.) You use the | |
Specifies a global alpha (transparency) value to apply in addition to the alpha value for a given color. Cocoa does not support this attribute directly. If you want to set it, you must use the |
|
Specifies whether paths use aliasing to smooth lines as they cross pixel boundaries. You use the |
Note: The winding rule used to fill paths is not stored as part of the current graphics state. You can set a default winding rule for NSBezierPath objects but doing so affects content rendered using those objects. For more information, see “Winding Rules.”
In a broad sense, Cocoa graphics context objects serve two types of canvases: screen-based canvases and print-based canvases. A screen-based graphics context renders content to a window, view, or image with the results usually appearing on a screen. A print-based graphics context is used to render content to a printer spool file, PDF file, PostScript file, EPS file, or other medium usually associated with the printing system.
For nearly all screen-based and print-based drawing, Cocoa provides an appropriate graphics context object automatically. Cocoa provides a graphics context object during all view updates and in response to the user printing a document. There are situations, however, where you must create a graphics context object manually, including the following:
Drawing to an offscreen bitmap
Creating PDF or EPS data
Initiating a print job programmatically
Using the class methods of NSGraphicsContext, you can create graphics context objects for drawing to screen-based canvases. You cannot use these methods for print-based canvas, however. Cocoa routes all printing operations through the Cocoa printing system, which handles the task of setting up the graphics context object for you. This means that if you want to generate PDF data, EPS data, or print to a printer, you must use the methods of the NSPrintOperation class to create a print job for your target. It also means that your views should provide some minimal printing support if you want to produce well-formatted output for print-based canvases.
Note: Although Cocoa does provide some support for creating OpenGL graphics contexts automatically, the default pixel format options are usually limited. In most cases, you will want to create a custom OpenGL graphics context with the pixel format options you need for drawing. For more information, see “Creating an OpenGL Graphics Context.”
You can determine the type of canvas being managed by the current graphics context using the isDrawingToScreen instance method or currentContextDrawingToScreen class method of NSGraphicsContext. For print-based canvases, you can use the attributes method to get additional information about the canvas, such as whether it is being used to generate a PDF or EPS file.
For more information about obtaining contexts for both screen-based and print-based canvases, see “Creating Graphics Contexts.”
The NSGraphicsContext class in Cocoa is a wrapper for a Quartz graphics context (CGContextRef data type). Both types manage the same basic information, and in fact, many methods of NSGraphicsContext simply call their Quartz equivalents. This relationship makes it easy to perform any Quartz-related drawing in your application. It also means that any time you have a Cocoa graphics context (an instance of the NSGraphicsContext class), you have a Quartz graphics context as well.
For information on how to use Cocoa graphics contexts to call Quartz functions, see “Using Quartz in Your Application.”
Last updated: 2007-10-31