Mac OS • 43:54
This session presents the specific functionality of Quartz, Apple's new low-level 2D drawing model for Mac OS X. We discuss guidelines for when Quartz should and should not be used, as well as details of the Quartz APIs.
Speakers: Derek Clegg, Mike Marinkovich
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Ladies and gentlemen, please welcome tech lead for Quartz, Derek Clegg. Welcome. Welcome to the last afternoon session, or the first afternoon session of the last day of WWDC. My name is Derek Clegg, and I'm going to be talking today about Quartz. There's my name. So what are we going to talk about today? Well, I'm going to focus on the rendering APIs in Quartz.
If some of you may have gone to Peter Grappanino's session on Wednesday, you might remember that there's two layers of Quartz. There's the bottom layer, sort of the Windows server, and the top layer. We're going to focus really on the top layer. That's the part you can use in DP4. We're going to talk about how you'd use Quartz in your application today, and also have a little demo.
So what I hope you'll learn by the end of the day is what Quartz is, when you should use it in your app, maybe when you shouldn't as well, what APIs there are that we have available for you, and how would you actually go about using the APIs in your application.
So you've undoubtedly seen this diagram many, many times, where the little part in the green box. And to spread that out a little bit, Here's a little bit detailed view of Quartz. So as I mentioned, there's really sort of the underlying-- Quartz, actually, just to clarify, Quartz is really sort of the orange piece in this diagram.
Underneath a lot of other parts of the technology is the Windows Server, the Core Graphics Services. That's the part that manages your screen real estate, brings Windows up and back from the display and so on. What I'm going to focus on is the Core Graphics rendering, the little part up in the upper left-hand corner. As you can see, the other technologies that we have live on top of Core Graphic Services, and those are, of course, available, and you're probably familiar with most of those. So what I'm focusing on is the newer piece, the rendering layer itself.
So what's Quartz really? Well, it's a 2D drawing engine. We're 2D only. We really leave 3D to other parts of the system. We're focusing primarily on just providing a really great 2D model. We use technology, or we base our APIs on Adobe's PDF model. The PDF spec is great. It provides a really great way of giving high fidelity images and pages for printing. We've adopted that pretty much wholesale. It's also a very clean, very nice API that we leverage.
What Quartz does on the back end, I mean, you know, you sort of tell us to do something. On the back end, what we're putting out is, of course, screen display. Anything that might go on the screen goes, in the long run, through the back end of the Core Graphics layer, of the Core Graphics Services layer. We also generate bitmap images. We generate PDF streams and PostScript streams, as well.
And Quartz, the whole package, is really the low-level services to get bits on the screen. Of course, the rendering layer is just one way that you get into the whole set of things, but in the long run, Quartz as a package is the way to get stuff onto the screen.
So what sort of API, I mean, what is this API that we have for Quartz? Well, as I said, it's the way to get into the rendering layer, and it's a really nice set of 2D drawing primitives based on PDF. Now one thing that I want to mention is what we don't really provide now in the API. We're not really giving access to window management. There's a lot of semantics about the way windows are managed. There's things like, you know, which little candy does what when you click on it. We're not really at that level. That's really the higher level toolkits.
So if you want to do any sort of window management, you should really go through Cocoa or Carbon. That's the right place. The other thing that we're not providing is machine-to-machine displays. So you can't sort of say on this machine, "Oh, I want you to draw something over here on that machine." We don't do any sort of that type of thing. Timbuk2 is an example of an app that does that.
So the question would come up, of course, well, there's this nice API. When should you use it? Well, It's a tricky question to answer. The truth is, Cocoa or Carbon are often the right thing to use. For one thing, Quartz is Mac OS X only. If your application needs to run on OS 9 and OS X, you probably should not use Quartz.
In that case, you should really stick with Carbon. For Cocoa, Cocoa has this nice object-oriented layer. It's all more modern and so on. We're very function-based. If you want that type of abstraction, you might want to go with Cocoa. Both those frameworks provide a lot more of additional things, like NSString and stuff like that, than we're providing.
But there are cases when you would want to use Quartz. A good example would probably be a situation, maybe you have an application where you've abstracted out the drawing piece of the application from the UI and the behavior and so on. And maybe that application lives on multiple platforms, so on Windows you go directly to GDI with that little drawing piece, and maybe on Mac OS 9 you've gone directly to Quick Draw. So a situation like that, maybe for Mac OS X you want to call Quartz directly in that part. That's one example. There are other cases where you'd want to, so it's really something that you'll have to sort of weigh for yourself.
Suppose you decided to use Quartz directly. This is sort of a general overview of how that works. Of course, you'll be calling Carbon or Cocoa, and they call into us. Cocoa calls into the rendering layer itself. Carbon, of course, will call down to the Core Graphic Services layer.
And then your application can call Quartz directly. So they sort of can all co-ex- well, Cocoa and Carbon can't necessarily co-exist, but your application call Quartz interleaved with calls that Cocoa or Carbon might be making to Quartz. You don't have to do anything special. There's no funky stuff that goes on to allow you to use it with- intermixed with the other frameworks. And of course, this diagram shows on the back end what's coming out would be screen rendering, PDF, PostScript, bitmap, raster data. So you get all of that for free, of course, because you're using Quartz in any case. So the Quartz display model.
Those of you who are familiar with PostScript or PDF are probably pretty aware of the way they work. It's basically a painter's algorithm. You take some paint and you put down some more paint on top and put down some more paint on top and so on. You just build up your image that way, sort of from back to front.
Now, because we have transparency, the paints are more like watercolors instead of oil things that are opaque, but you nevertheless get a nice image out of it as you're building it up. We're also-- From the ground up, we've striven to be device and resolution independent. So we're not really dependent upon the number of dots per inch.
We're not really dependent upon the number of-- what your pixel depth is and stuff like that. We're really going for a situation where when you use the API, it doesn't matter where you're going to a printer or going to a screen display or any particular type of screen display, you should get the same nice results. So your application doesn't need to worry about that.
For font support, of course we support TrueType. We've had that for a long time. In developer preview 4, we've added support for Type 1 that's not completely finished, so you will notice some places where it doesn't quite work. Excuse me. But that will certainly be done in a future release.
And of course we have CID font support. CID fonts are used for languages where there's a large number of glyphs. Chinese or Japanese are good examples. And you need something a little bit more sophisticated to manage the big glyph set in order to show text. So we have support for CID fonts as well, both the CID TrueType and CID Type 1.
And then we're also, because we do care about device independence and so on, we also support device independent color. And we leverage ColorSync for that, and Apple technology does a great job of giving us device independence for color. And then one thing I want to clarify, some people have asked me, well, you know, they remember the days when we used Display Postscript.
And the model there is you have a client and a server, and if I say to the client, "Draw me a rectangle," a little byte stream gets wadded up and gets sent over to the server, and the server interprets that byte stream and says, "Oh, draw a rectangle." The rectangle gets drawn. We're not that. The Quartz display model doesn't use sort of a PDF stream in between the two, the client-server side.
Instead, we share memory. The client and the server have a single shared memory buffer. And on the client side, you say, "Draw me a rectangle," it gets drawn right there. The server takes it and flushes that to the screen. So there's not some intermediate representation, and that's a concern for some people who are worried that it might not be efficient.
So let me give you an overview of our API. As I said before, we're very low-level. We're entirely in C. No objective-oriented stuff, no Java, no other things. And because we're trying to maybe increase consistency with other parts of the system, we really do try to follow the core foundation style, both for naming, conventions, and other things. So as a consequence, the names are all pretty much exactly the same style.
So there's CG, the prefix, everything starts with CG so that you don't get the namespace pollution you do in other frameworks. There's the class, and I use that pretty loosely. I don't mean that in an object-oriented sense. I mean that as sort of the collection of common functions that this function belongs to. And then a verb and an object, so do something to something. Here's an example, CG context show text. show some text in a context.
And we'll get into that a little bit more down the road. So what sort of classes, collections of functions do we have available? These are a few and I'm going to go into each one of them in a little bit more detail. Get a little bit more water.
So, affine transforms. What we do is we model collections of data just as a C struct, right? There's really nothing special about it. It's a simple C struct that provides all the data you need for a particular thing. An affine transform is one example of this. We have some functions that let you create and use and modify the affine transform.
An affine transform, for those of you who are not familiar with them, is a 3x2 matrix that lets you transform a two-dimensional space in a very nice way. You can do rotations, scaling, skewing, pretty much the standard sorts of things that you might do if you were trying to do a pretty straightforward display of things. Whoops. The nice thing about affine transforms is that they form a group under multiplication. So if I scale or skew something and do this, I can do this. those two things one after another, what I end up with is another affine transform.
In Quartz, what we use them for is transforming our user space from one orientation to another. We can use them to flip or rotate, the type of stuff that you might want to do if you're doing drawing. We have a couple of convenience functions. There's functions to create a rotation or a scale. We also have some other ones, some simple ones. For example, CG Affine Transform Invert takes an Affine Transform and inverts it.
We also have some geometry structures. In this case, we have points, which are just an X, Y position in space, a size, which is a width and a height, and a rectangle, an origin, a point in space, and a width and a height. They use floating point values for the representation of the data because we're basically a vector-based drawing model. We really want to have the device independence, and floating point works very well for that. The functions we provide in terms of manipulating these objects are pretty simple.
You can create one, of course. You can do some simple rectangular operations, such as intersect two rectangles, get a rectangle, or union two rectangles, and get the rectangular union. There are some convenience things, such as this example, CG_REC_CONTAINS_POINT_RETURNS_1, if a point is inside a REC. That can be useful for certain applications.
So what I've talked about so far is some pretty, those are, you know, you can imagine, very simple structures. Now we're getting into something a little bit more complicated, a little bit more data associated with them. Color spaces are the way, are the collection of information we need to represent a color in Quartz.
We have functions that let you work with device-dependent and device-independent colors. Device-dependent colors are, well, let me, device-independent colors, that's very important when you have, for example, a magazine illustration. Say you want to scan it in and bring it up on your screen and you want the red value here to exactly match so that the page here and the display here are exactly the same. You don't want to use device-independent color in that case because you really don't want the, you want the color to be independent of the device it's being represented on.
Device-dependent colors are more useful when you don't care so much. You sort of, you scan it in, but you want like a nice red value. You wouldn't want some blue value or something, but you're not precisely concerned that they match 100%. So both of those are very useful in different contexts and they're both, we support both of them. What we provide in Quartz, what we use in Quartz to represent a color is just a C array of floats.
So we're not doing anything more special than that. Typically for like, for example, RGB, you'd have three float values. CMYK would be four float values and so on. We. Have convenience functions which let you specify an RGB value directly, but we're not, but in, you know, the primitive is an array of floating point values.
So, what color spaces do we really provide? In the device-dependent color spaces, we support gray, which is just a monochrome 0 to 1 value, black and white. RGB, which you're familiar with, of course, for screen displays, and CMYK, which is used in printing. Device-independent colors, the two special cases are calibrated gray and calibrated RGB. Those are both essentially subsets of ICC profiles. Some of you might be familiar with that from ColorSync, which uses those.
To specify a device-independent color, the calibrated gray and RGB are just simple special cases of those. But we do, using leverage from ColorSync, we do have support for the full range of ICC profiles, so you can work with those as you need to, if that's what your application requires.
You sort of have the device dependent and device independent color spaces are sort of two axes. Indexed is a little special. Indexed works by essentially associating with a number from 0 to some higher number, 0 to 255, for example, for each one of those numbers is associated a single color and a given color space. It's a way to sort of compactly represent a set of colors that really aren't the full range of all possible colors.
GIF files, for example, some of you might be familiar with those, use index color space essentially where each number from 0 to 255 represents a single RGB value for the image. So we support those in Quartz and they can be very powerful in some circumstances. An example of the functions that we have, CG color space create device RGB creates the device RGB color space.
Now, we also have support for images. In our parlance, images are two-dimensional arrays of sample data. You have a width and a height, you know, a bitmap, right? A width and a height, for every pixel, you have a pixel depth, number of samples per pixel, might be RGB, for example, would be three samples. In addition, the image can have an alpha channel, so it can basically specify coverage information.
So not, if you don't want all of the image to be displayed in a big rectangle, you would use the alpha channel to knock out parts of the image when you're displaying it. We also provide a function to let you create an image mask, which you can think of as just pure alpha coverage.
It's just coverage information, and you would use that typically to draw a color through there, and so you'd end up with a, with a color. It's just the parts where the, where the coverage mask was non-zero, actually drawn on the display. An example, a trivial example, CG image create, though it does take an awful lot of arguments to actually create an image.
So what I've talked about so far is really sort of data-bearing objects. They don't really have any behavior associated with them. They just sort of contain information, contain state. And those are useful, but, you know, it's like, well, they don't do anything. So the drawing context is actually the thing that carries behavior in Quartz. It's the thing that does something. You can think of the drawing context as your connection to the device. The device might be the screen display. It might be a PDF file that you're creating. It might be a bitmap.
But the drawing context really is associated with the thing that you're drawing to. Now, in addition, it's not just the connection. It actually maintains state for you. Similar to QuickDraw, we actually have a model where you set a bunch of state, and then you ask the drawing context to do something for you.
So you might want to draw a dotted rect, for example. So you would set the dash pattern, and you would set the line width, and then you would say, oh, now go draw the rect. When that rect gets drawn, it uses the information from the graphic state to display the rectangle.
And, oh I should just mention, these are some of the things that are part of the graphic state. Now, it's nice to have a graphic state, but it's even nicer to have more than one. We actually allow you to, again following the PDF PostScript model, you can save the graphic state. So you essentially are making a copy of the current state. And then you can modify that to your heart's content. When you restore it, you go back to the original one.
So that's really important if you don't want to interfere with other people's drawing. You save the graphic state, change whatever, and then restore it. You don't have to track that information yourself. It's a stack, so you can save and save and save and save and save the graphic state. And then you can restore, restore, restore, restore, restore, and you get back to the original graphic state that you're in. So that's actually a really nice property. And again, that follows the PDF PostScript model very closely.
So what sorts of things can you do to a drawing context? These are all parts of the graphic state as well. You can modify the display transformation. That's used if you want to, for example, draw a rotated piece of text. You might change the display transformation, rotate, draw your text, which will go drawn in a nice angle, and then you might rotate back. Again, we're using the affine transform to specify-- that's the sort of the primitive. The full affine transform specifies how the display is transformed or how your drawing context state is transformed. There are convenience functions for doing a simple rotation or a simple scale.
Then the heart of what you do in a graphics context is you specify a path. You specify a path to draw something, to fill, to stroke, whatever. But the real meat of it is a path. In Quartz, we're really going for something as simple as possible, but not too simple.
Every path in Quartz is composed of three parts: a line, or a collection of these, a line, a Bezier curve, or a quadratic curve. Everything else is built up from that. We do have in the API convenience functions for creating an arc, but we approximate that by a sequence of Bezier curves. We also have functions for working with rectangles, because those are just so common that it's silly to have to build that up every time yourself.
Now once you have the path specified, you want to do something with it. What do you do? Well, again, we're following the PDF model here. Typically you want to fill the path or you want to stroke the path. Those things are often done with different color. It's pretty rare you fill and stroke it with the same color. So those two things are split out. There's a fill color and a stroke color. There's also a fill and stroke color space because since the color itself doesn't convey any notion of how to interpret its values, You also specify the color space to the graphic state.
I mean, as part of the graphic state. And then, as I said, once you've set a color, you can fill the path, you can stroke the path, you can fill and stroke the path in one operation, sort of a sequence of things like that. And then another nice thing that you can do is, once you've specified a path, and it can be any path you want, you can clip to it. What that means is that from that point on, nothing will be displayed outside of that path's region.
And then it turns out that the clip region is part of the graphic state, so you can actually do some really nice things. For example, maybe you want to draw a nice picture of an ocean through a porthole. So you might draw, well, what you first do is you'd save the graphic state, because you don't want to screw up other people later.
You draw as part of your path a circle, you clip to it, and then you draw your image of the seascape in the background. Well, nothing is going to be drawn outside of that circle. So you'll get a nice image. You'll get a nice image of the seascape through your porthole.
Then we do a restore of the graphic state. You're back to the original, and the clip path is gone. And so now you can draw any other part of the, maybe the rest of the room or something. So that's actually a pretty nice thing that the clip path is part of the graphic state.
Oh, and I should also mention in terms of paths, it's not just a single, say, a single arc. I mean, a path could be disjoint pieces of like a line, a rectangle, a circle, a circle, a circle. That whole wad would be considered one path that you can work with.
And then finally, for the drawing context, clearly you can display an image. Once you've created one, you can draw it. It respects the parameters of the graphic state. So if you've rotated it and you've clipped it, that image will be clipped and rotated exactly as you want. We handle all that stuff for you. You can select fonts in the API, and then you can display text.
So I should mention with displaying text, we're not really in the business of Unicode display. The functions that we provide are pretty basic. Go to a point and show some glyphs, show some characters. If you want sort of Unicode translation and that type of thing, that stuff's really hard, and you should really go to a higher-level framework.
At Sui, Carbon, both those provide functions to allow you to do this. Cocoa has a great text display layout system that is all Unicode-based. So really, if you want that type of thing, and you want to go to a higher level, we're working at a little bit lower level. But it might still be sufficient for your needs.
Now, of course, Steve showed a bunch of PDF files getting displayed. Peter Graffagnino on Wednesday talked about PDF. So one question you might have is what sort of things can you do in the Quartz API with PDF files? Well, in DP4, at the level of the Quartz API, we don't have functions that are public for you to use.
If you want to do, for example, a page display, you really should probably go through Cocoa, or Carbon, I should say. Here in Cocoa, you can create an NSPDF image rep that will display pages for you. If you're Carbon, you can use a QuickTime graphic importer. Unfortunately, for DP4, we don't have API in Quartz that lets you directly display a page from a PDF file.
We will in a future version, which I think will be very nice. A typical example might be if you had a PDF file that contained your logo for your business, and you just draw it up in some part of your screen, and then you'd fill in the rest of it with either Cocoa, Carbon, or Quartz calls. And of course, it's just like an image in that respect. It will respect all the parameters of the graphic state, so you could rotate the PDF file, or scale it, or skew it, whatever you want. All that stuff is handled for you. All right.
We'll also provide, post-DP4, support to create a PDF drawing context. I'll talk a little bit later about how you actually get a hold of a context. Right now, though, there's no way to sort of create one of your own that you can then stream PDF to. Post-DP4 will let you, will give you API that will let you create a PDF context. You can do a whole bunch of Quartz calls into it, and what comes out on the back end will be a PDF file.
So, how would you use quartz if you actually decided to in your application? I'm not going to talk too much about Cocoa, basically you want to get a context for NSVU. There's a good example, a small example of how to do this in the Sketch example. It's I think in system library, or system developer examples, sketch.app or roughly that, you'll find it. And that's actually has an example of how to do this.
For Carbon, which probably more of you are interested in, the way you get a drawing context to work with is from your graph port. And they're really, you can think of them as like a one to one correspondence. If you have a graph port, you can get a drawing context. As I said before, you can keep using the graph port while you're using the context. There's nothing that sort of stops you from doing one or the other.
Post-DP4, as I mentioned before, you'll be able to create a PDF context that you can write to and PDF comes out on the back end. We'll also provide you with a bitmap generation context. For example, you can create an image for a bitmap that has all of the coordinates drawing in the bitmap that you can then take and convert to a JPEG file or maybe send it to a printer or some other use for it. That will be available post-DP4.
So if you decide, oh, I want to use this API, it's really cool, where do you find it? The header files are in the core graphics framework. Somebody the other day was asking me, I don't see any Quartz frameworks anywhere. And that's because they're in the core graphics framework. For DP4, there's documentation in the header files.
There's comments before each function. I realize it's not official documentation, but it's available in DP4. Post-DP4, we should have documentation available on the developer website. We'll also probably have some examples of code that uses Quartz, and you can use that to get an idea of how to use it.
I believe the demo we're going to show you later will be up shortly. So now actually I'd like to show you the demo and I'd like to welcome Mike Marinkovich up on stage, who's going to lead you through how he used Quartz in his Carbon application. Well thank you very much Derek.
So as Derek mentioned, what we're showing today is a Carbon application. What makes this Carbon application special is the fact that we've modified it to take advantage of core graphics. So, this application's been a long time in the making. It's been started off as a Mac OS 8 app.
We eventually ported it to Carbon, and now we've modified it once again to take advantage of Core Graphics. So the first thing we did to create this Core Graphics project is we moved our source files over to Mac OS X, and we created a project builder project, imported all our source files. So, what you're seeing up on the screen is our project builder project called Carbon Draw. Carbon Draw is a vector-based drawing application. It's Carbon, but it uses Core Graphics for its rendering.
So a couple interesting notes. Derek was pointing out the frameworks usage. And one thing we had to do to our project was import the core graphics framework. And you'll see here where the mouse is, we have imported that. And that's under the project menu, add a framework. And that is in system libraries frameworks, which you've probably heard a lot of this week. So from here, why don't I launch the application, and I'll show you what we've done.
Hopefully it doesn't have to recompile. So at first glance, you'll notice the app looks like any other Carbon app. It's got standard event manager calls, standard window dragging, event handling, even Apple events. It's just a regular old Carbon app that we call Core Graphics. So the first thing I'll show you is a line, simply. And this app allows us to resize the object, drag it around, can make the line width a little bigger, drag the object around.
So one of the great features of Core graphics is the fact that we have anti-aliased graphics. So to demonstrate this, I will bring up a little app that shows us effectively fat bits, and you'll notice that the edge is anti-aliased. So we have real clean-looking, nice graphics with Core graphics.
So another feature we took advantage of was line caps. Now, if I make this a little bigger, you will be able to see that we have Quartz is a flat end on this. And what this is, is this is the butt line cap. Now the butt line cap is rendering from the origin to the destination and giving you a square end.
Well, we also have other line caps, and one of which would be the round line cap. So we have a nice round edge. And once again, if I bring up the fat bits application, you'll notice that it's anti-aliased as well. So we can also apply the square line cap, which gives you relatively the same as the butt line cap, except for the rendering occurs half the line width before the origin and half the line width after the origin, giving you a square pen.
So, besides that, we're able to apply some other aspects to this object, such as Derek mentioned, LineDash. So if I make this a little smaller... We can apply a line dash to this, and this will give us, in this case, just a square line dash, but since the dashes are all individual lines, we can apply a line cap to each one of those.
So if I can apply I can apply the round line cap to it as an example, and we have round line caps on the individual lines, and I can also apply the butt line cap. We supply the dash to Core Graphics as an array, so if we had, in this case we're using an array of two items, a length of the dash and a length of the space, but you can also apply as many as you would like. So if we wanted to make the dashes smaller and say apply the round line cap, we could have little round circles as our line dash.
So from here, a lot of people have asked if we can actually render with Quickdraw and Core Graphics into the same buffers. Well, what we're doing for our selection process is we're using Quickdraw in XOR mode to render the line. So if I drag this out, you'll notice that we're using XOR mode and the edges are fairly jagged. That's Quickdraw.
And you'll also notice that the ends of the line, the line caps, are pointed, which is the effect of Quickdraw's hanging pen drawing algorithm, which is really far from optimal. If you look at the Core Graphics line above it, you'll see much nicer graphics. So I release that and we have a Core Graphics object.
So from here, I'll delete these two items. I'd like to show you rectangles. So as with Quick Draw, in Core Graphics, we can draw rectangles, and we get the anti-alias graphics as well. So if I make this a little bigger, I'll show you another feature, and that is line joins.
So in Core Graphics, you can apply a line join to this item, so wherever the lines meet, in this case with the rectangle, you have four corners, you can apply a join. So what we're seeing here is the mitered line join. We can also apply... Other line joints such as round. So now we have rounded corners and I'll bring up a little fat bits to show you the rounded corners again.
And for you QuitDraw folks, you'll notice that the interior of the rectangle is still square, which is different from QuitDraw's rendering algorithm. So we can also apply another line join, which is the bevel line join, which is another nice effect. So from here, I'll also show you that we can apply line dash to this object.
So what we have here is we have the butt line dash, and I can apply all the other line dashes to it, or the other line caps to it. So you'll notice that here we have rounded, but we still have our Our line join application to this. So, in this case we have bevel, and if we move this around, you'll notice that the corners are beveled, but yet we have a rounded line dash. So it's an interesting effect.
So, another interesting thing is that Core graphics can interact with the rest of the toolbox, or I should say it's easy to interact with the Carbon toolbox. And for the demo, we set up a fill color. So, I'll bring up the color picker, and we're looking at the standard Mac OS color picker on Mac OS X, the crayons. We'll pick a new color, let's say yellow, so it's not too bright.
Okay, and now we have a fill color of yellow. Well, what this demonstrates is it's easy to convert an RGB color, a Macintosh RGB color, which is four shorts, into a floating point RGB color, the more modern floating point RGB color that Core Graphics uses. And we can also change the stroke color, just so I can show you that we can actually do this. Pick purple. So from here, I'd like to move on to something else. I'll try and pick a little bit more useful colors. I don't want to blind you.
So we can also draw ovals, as Derek mentioned. So we have an oval with nice anti-aliased edges, which is a nice change. And we can also apply the line dash to this. You'll notice you can resize this, and Core Graphics dynamically reconfigures where the dashes are and even get the nice bending effects in the corners.
So, there are other architecture changes that we took advantage of in this application that aren't apparent here. On the old Mac OS 8 application, we used an off-screen to buffer all these objects and copy bits them to the screen. Well, that was quite a bit of work and we also had to do... We're going to be rendering in different spaces. So we'd be rendering in our off-screen when we really wanted to show it on the screen and so forth and so on. So what we're doing in this application is we've taken advantage of the fact that the windows are buffered.
So we render directly into our window, and when we're done rendering we just call flush. The graphics system keeps track of what we've changed in the window, and it flushes only that that has been changed. So we can get relatively flicker-free, if not completely flicker-free drawing by using this method. So if I... Create a few objects here. All going to be the same color, but maybe I'll set the background color.
Something a little different here. You'll notice that we can drag these objects around flicker-free. Hopefully on this display it's flicker-free without doing too much work. So we've taken advantage of the low-level architecture for our buffering. So from here, I'd like to turn it back over to Derek, where he is going to talk about some of the techniques we use to make this application possible. Thank you.
[Transcript missing]
As a second example, here's how we draw the ovals that Mike was showing you. What we want to do is play a trick. Instead of actually drawing an oval, what we're going to do is draw a circle. But we're going to scale the drawing context so that we actually stretch it out to get a nice oval. That's a pretty convenient trick because it's really hard to actually do all the math to figure out how to draw the oval. It's really nice to just draw the circle. So what do we do? Well, we begin by saving the graphic state.
We want to have our changes not affect other people. Then we do begin path. We start a path. And then we scale the transformation matrix. We scale an X and Y by the amount we want to stretch so that we get the oval. We then add an arc to the path.
This is one of the convenience functions I mentioned earlier. This takes a center radius and then an angle, 0 to 2 pi in this case. We're going to draw the whole circle. And then whether it's clockwise or counterclockwise. And then we close the path. And then we... Once we've... We've done that. We specified the path.
We fill it. We just fill it with the current color from the graphic state. And then because we're done working with the graphic state, we restore it back to what it was. You want to have those things balanced. So that's a pretty simple example of drawing an oval. Most of the demo has about as much code as this for each one of the different little pieces. So Quartz does an awful lot for you.
So just to summarize before we get to Q&A, what we're providing is a pretty straightforward low-level 2D API. That's the goal, and that's, I think, what we're providing. You want to sort of think about using Quartz when it makes sense in your application. It probably doesn't make sense to write your whole app in Quartz. I don't know, maybe, but I would think not. The toolkits above, Cocoa and Carbon they're great. They have lots of things available for you to work with. There will be times you might want to drop down to the level of Quartz. When that makes sense do that.
But you're going to have to decide that question for yourself for your own application. And then finally we're not done. The API that is in DP4 is our first set of API. We're not going to take anything away, but we're planning on adding more. So as we get feedback and as we think about more things to do, we'll be adding more API for the future. So we're really interested in having your feedback to sort of help us focus what we need to do next.
The people to contact if you want to actually send email to some human being. John Signa is our technology manager. You can mail him. David Wright is our application manager. He's our communications technology manager. You can mail him. It's not on this slide, but there's an email address, [email protected] that will go to us. And you can certainly send any email you want to that address.
And we'll take a look at it. For those of you who are interested later today, I guess actually right after my talk in this same hall, we'll have the Mac OS X advanced printing session that will probably touch on some aspects of Quartz. And then a very important thing. We're going to be open until 5:00 on Friday, the last day of the conference. But we'd really love it if you could make it to the feedback forum for graphics and printing. It would be super if you could do that. So I'd like to have the people in the team come up, and we'll have some Q&A.