Application Technologies • 56:41
Come for an in-depth review of the Web Kit APIs. Learn about plug-in development, and see practical examples describing how to use Web Kit beyond the simple browser-in-a-window implementation.
Speakers: Tim Hatcher, Tim Omernick
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. I'm Tim Hatcher, and welcome to Advanced Web Kit Integration. Today we're going to talk about some novel uses of WebKit, some key APIs that you need to know about, what's new in Leopard, and Tim Omernick, my colleague, is going to talk to you about plug-ins later on.
So let's talk about some novel uses of Web Kit. First, there's Safari. Probably the most un-novel use of Web Kit there could be. It's just a browser. Out of the box, Web Kit behaves just like it would in Safari. Two years ago, we released Web Kit as an API that you guys can use in your application. And there's been many uses of Web Kit since then. And here's just a few of them.
Out of this, you'll see some trends, such as chat applications. Pretty near and dear to my heart, as some of you might know. But chat applications really can take advantage of what Web Kit as an API has to offer. You can do advanced styling, you can append and modify content live. It's really what a chat application needs to do, and that's what Web Kit lets you do right out of the box.
Another great category of these applications that are the family of Web Kit applications are web development tools. This makes a lot of sense because you're using the same technology that Safari uses to display the content to the end user. And some examples: SandVox from Corellia and Xile Scope.
One other key application that you want to do a live preview of that's kind of picked up on Web Kit in recent years is blog editors. There's a lot of blog editors that use Web Kit to style and display a live preview of exactly what you're going to post on your blog. So you can see it, and you can exactly see how it's going to look when the user goes to your site. So out of these applications, who all of you are using Web Kit in your application? Let's see some hands. That's great.
So hopefully today you can take the knowledge you've learned and go back and start using Web Kit in unique ways such as these applications and find new ways to use Web Kit and integrate it more with your application to show content, to show styles, to show previews of things that you want your users to know about. It doesn't have to be web-related.
Your application can be just a regular application, a Cocoa application, and you use Web Kit in one little piece for a registration pane. You can use Web Kit in a lot of places, and hopefully with what I'm going to talk about, I'll help you start using Web Kit in those ways.
So some key Web Kit APIs that you want to know about. These are fundamental pieces that you'll want to know if you're going to start using Web Kit in a normal application. Most of you probably aren't going to go out and make a new web browser. Safari's the best one, of course.
I want to know about the Document Object Model. Not a whole lot of you probably have used the Document Object Model, unless you have a lot of history with web development. So I'm going to go over the Document Object Model a little bit. So what is the Document Object Model? Every web page has a structure of HTML and content.
When that gets parsed by Web Kit, it turns it into what's called the DOM. And this is a standard set up by the W3C. And it allows you to interact and programmatically change or access anything that's in that HTML file. So it's a tree-based structure. And you can access it from JavaScript or Objective-C.
So I mentioned it was a tree-based structure. Here are some of the key properties and methods that you're going to be using when you're using the DOM to access this structure, such as parent node, next sibling, child nodes. So you can traverse and modify the tree with these other methods, insert, append, remove. Very common names, and these are all standard names set up by the W3C. And the names are used in JavaScript in Objective-C, so if you're used to it in JavaScript, you can just use it in Objective-C.
So those were the node properties. You can also access a special type of node, which is the document. It's the main node of the tree. It's what you use to get access to everything else that's in that tree. So you can get access to the document element, which is going to be your HTML element. You can get access to the title, the body. You can also get access to style sheets and use the style sheet DOM.
Some other methods that you'll be using all the time from the document are getElementById and createElement if you're modifying the DOM. So let's talk about some of those. Here's an example in JavaScript using createElement and createTextNode, and I just append it simply to the body. And you ask a document to create a new element for you, and you pass in a tag name, and create a text node based on a string, and then you can append it.
So here's the same example in Objective-C, no JavaScript included. So you can do the exact same thing in Objective-C. And this has been available since Tiger, and it's also available in the 10.3.9 update in Panther. So you can really use Objective-C DOM access in your Web Kit applications now. And it's really great for optimized code paths. And as you can see, we're using the same naming schemes as the JavaScript access. So it's all the standard names from the W3C. And you can see the JavaScript and Objective-C are very similar, just syntactical differences in the language.
So I talked a little bit about adding content, making new DOM nodes, doing things like that. What if you have some HTML that comes in over the wire, like in a chat application, or some other text that you read from the disk, but you can't point Web Kit directly at it? Here's some ways to inject and read in HTML directly from the DOM.
It's an extension set up by Microsoft in their Internet Explorer, but all browsers have added inner HTML support. You can get access to the HTML text, and you can also set it using this property. So here's an example that gets an element by ID, like I said, the preferred way of getting access to an element very quickly.
Tim Hortons, and I'm changing the inner HTML to say hello WWDC in bold. And that'll be parsed, and here's an example of what it would look like if I re-serialized the DOM back out. It would have the new HTML injected inside and replacing everything that's inside that div.
So that's how you use the DOM to modify what's in a web view. So let's give a demo on that. I have an Xcode project. Like I said, chat applications have started using this almost exclusively in their web view. So I'm going to give you a little demo of a simple chat application. It's written in a few hundred lines. It doesn't do any network or anything. It just locally echoes everything to the web view. So I have an HTML file.
: I'm Tim Omernick, and it's part of my application resources. I also have some supporting CSS and JavaScript. And in my nib, I just have my web view wired up, and I also have a text input field. All very simple and common for a chat application. So let's look at the code.
In my Nib, I have this class set up as an instance, and in the Awake from Nib, I just tell the WebView to load a document. And there's many ways to tell WebKit to load an HTML file. This is the preferred way. You're using a request. There's other ways to load a string, but if you can really load from a disk, that's the best approach.
So I have send chat message hooked up to the action of my text field. And what I want to do in this is make a new DOM element that then gets appended at the bottom of the HTML file. So here's the structure that I'm going to be creating in code using DOM calls.
So I put this little comment here to give me a guide on what the HTML is actually going to look like, what my goal is. So whenever you're accessing the DOM, you're probably going to use the document. You always need the document, so you might as well just assign it to a local variable or a class instance variable.
So, like I showed in the earlier example, I can create an element, and in this case, I'm creating a div. A div in HTML is basically a simple block. So if you need to do any blocks, you want to use a div, and I'll show that in my demo. message element. One thing I'll talk about a little later, but this is using a style class. I have this style message set up in my CSS file. Div will now use this style that I have loaded in my HTML file.
One other thing that's common in a chat application is to have a username. So I'm going to create a new element that's a span. And a span is an inline element, so text will flow next to it. I'm also going to set a class name for user, and that's defined in my CSS file. I'm also going to set the text content. This can be whatever the username of the local user is. In this case, it's Xenon, which is my nickname.
I'm also going to create a DOM text node, and you do that just like an element, talking to the document to get a text node. You might be familiar with core foundation. Every time you ask for create, you have to then release an element. Not so in the DOM.
The DOM has some conflicting naming schemes compared to core foundation, which most of you are familiar with. When you ask a document to create a text node, we return you an auto-released version. The document is really holding onto that for you, too. You don't need to release it. It's part of the document.
So I have the text of my message. I just pulled that out of the text field. Now I'm going to combine those two and append that in order, the username and then the text message, to the message element, which wraps everything based on the little template that I was using. So I have my message element, my username element, my cool message, and those are all our children of the message element. So that's where this happens. We also now have the capability in Leopard to add event listeners through Objective-C. I'll talk about this a little bit later.
Now we have our message element that contains the username and text. So now I want to append that to the body of the document. And in most chat applications, you want to scroll down, so you would do this code. I'm not going to talk a whole lot about that. and then reset the input field. So let's see how this works.
Bring up. I have a simple chat application here with the focus on the text field. And my background of the document is blue, and there's nothing loaded in the document. So I can type in a couple messages, and you'll see it gets appended as you would expect. And Web Kit handles all the resizing, just like an HTML file. You don't have to worry about doing all the drawing code. Notice in my DOM, I'm not telling it how to draw.
That's part of the CSS. Which you should go out and learn if you're going to be using Web Kit. I'm not going to go over how the CSS syntax defines how the look and feel is. But CSS and HTML are fundamental things that you'll need to know when using Web Kit. So that's a simple chat application. And if I put more messages, it auto-scrolls to the bottom. So that's how you append live content to a web view. Back to slides.
So I talked about style a little bit. I was using class name. There's other ways to access the style, but I'm mainly going to talk about class name. You can also get access to the style property and modify properties individually. Classes are the best way to go. Here's an example that defines a couple CSS rules on things you can append and tell your div or element to use.
Here's an example in Objective-C. I get an element by ID. Again, the best way to do element access. Use the setClassName property or method, and now I'm telling this div or element to use the class name hot. So now it's going to inherit those CSS rules that are defined in my style sheet.
You can also, confusing, but you can do this. The class name is not just a singular name. You can supply a space-separated list of names to use. So now this header headline will inherit from both hot and large style rules. So now the color is going to be red, bold, and 20 pixels tall. You can see the benefit of doing this. So let me show you a demo using the same chat application. Back to the demo.
So here's the chat window that I have up. And remember that event listener that I added to the code. I'm listening for click events, and I've registered this class as an event listener. And to do that in Objective-C, you need to conform to the DOM event listener protocol.
And the only thing defined in this protocol is the handle event method. I'm listening for click events, and I've registered this class as an event listener. And to do that in Objective-C, you need to conform to the DOM event listener protocol. And the only thing defined in this protocol is the handle event method.
I'm listening for click events, and I've registered this class as an event listener. And to do that in Objective-C, you need to conform to the DOM event listener protocol. And the only thing defined in this protocol is the handle event method. And you can get access to the DOM element that was clicked by asking the event for its target. It's as simple as that. And now I can use the set class name to modify the style of what was clicked.
And in my style sheet, I have a special rule Tim O' That I use alongside of message that changes the background color of anything that's clicked. So a way to flag a message or do other actions style-wise to the message that was clicked. So let's see that in the example. So I can click on any of these elements and the style changes and updates and WebView re-renders that information based on the new style rules that I've passed in. So back to the slides.
So class name is really the best way to take advantage of style sheet manipulation in Web Kit. You don't want to be in the business of modifying and adding properties on the fly. You can do that, and there are certain cases where you want to do that, and I'll show you more about that later.
But if you have a set of rules that you want to apply to an element, going back and forth between different looks, you want to switch the class names. And that's the quickest way because Web Kit can cache that rule, and it doesn't have to reparse the CSS every time.
So now we're going to talk about WebView delegate methods. WebView is full of delegates. Normally, you only have one delegate in your Cocoa or AppKit class. But WebView has so many delegate methods, we broke it up into five logical groups. And those are user interface, frame load, resource load, policy delegate for navigation changes, and the editing delegate, which we added recently.
[Transcript missing]
Using these delegate methods, I really didn't show in the demo. Can we switch back to the demo? In my WebView, I haven't turned off anything. So notice the context menu still shows a context menu. And I can drag in an HTML file, and WebView will then change to show that file.
But in your application, you probably don't want to do any of that, because you don't want people to be modifying what's being displayed. So can we switch back to the slides? So one thing you want to do is prevent page changes. When a file is dragged or a link is clicked in your web view, you want to handle those differently in an application versus a web browser. So you want to override or define this delegate method, this policy delegate method. And you want to get the URL that we pass in.
You can then check the schema or URL for the types you want to allow. And on the previous slide, it told you you want to allow the about blank URL. That's if you're using load HTML string or load HTML data. Those are memory loads. They don't have any URL associated with them. So Web Kit's just going to use the about blank URL. So you want to allow that if you're using any of those APIs.
In my example, I used a URL and told it to load it from disk, which is the preferred way of loading content into a web view. So you can check and allow the files that you expect to be loaded. And you should also pass off any URLs that you don't want to handle by sending that through NS Workspace. Listener ignore. We pass in a listener object to these delegate methods, and if you say listener ignore, then the WebView will not load any of that content. Calling listener use will actually tell WebView to display that content, which I do in these other two examples.
So I talked about context menus also. In my example, I had a reload menu, and that would actually reload the WebView back to its original state. You probably don't want any of your users doing that. It's probably handy for you to do when you're developing or testing, but you don't want that in your shipping product. So you can use this UI delegate to change or modify or totally suppress the context menu that shows up.
And by default, Web Kit will show like a reload, a back, and a forward. It also shows you copy and paste, which you probably want to keep. But you want to totally suppress anything that you don't want to show up for your shipping product. So that's some of the WebView delegate methods, just a few of the key ones that you want to implement if you are actually using WebView in a way that's not like a browser.
Now let's talk about the Web Scripting API. This has been a little confusing for people, so I want to clarify what exactly you can do with this API. The general sense of what it allows you to do is bridge objects from Objective-C to JavaScript and back and forth. So you can call a method on your Objective-C class, and you can also call a function back into JavaScript.
There's some required methods that you need to implement. The documentation is a little confusing on this, but you need to implement these methods, or your bridged objects will not work in JavaScript. So isSelector excluded from JavaScript? IsKey excluded from JavaScript? The selector means is this JavaScript method excluded, or is this key, meaning a property that's going to be exposed into JavaScript. And you want to return no from any of these methods that you want to actually expose that selector or key to JavaScript. And you don't need to worry about calling super.
So here's an example. I have a simple class that just has a my action that I want to expose to JavaScript. And in this case, I need to return no. So I want to tell that script, that object to expose my action to JavaScript. And if I have a property name that's in my class, I can expose that in the is key excluded. That gets exposed as a property in JavaScript.
So the default names are kind of ugly. When going from Objective-C to JavaScript syntax, Objective-C has a lot of colons. It's not your typical language where everything is passed in as an argument list. Objective-C spaces them out with colons. So if you have a selector that has three arguments, you really want to clean that up.
By default, it's going to look very ugly like this, where you have underscores, and that's not a common practice or look in the JavaScript language. So you really want to change it and make it a more terse name and common name to be used in JavaScript. And this looks a lot better and is more familiar to those that... use JavaScript daily.
So now that we have our methods and properties exposed to JavaScript, you want to bind that when the page loads. And you typically bind it as an object that is on the window object. And anything on the window object is implied. So if I give it a key name of sprite, it's really window.sprite. But you can also refer to it as just sprite. That's a thing you can do in JavaScript.
So in this example, I'm using the Windows Script Object Available delegate method to bind any of my Objective-C objects to their JavaScript counterpart names. And in this case, I allocate a sprite, set it using simple set value for key. And the key is, like I said, going to be the name on the Windows Script object that you can access through JavaScript.
I've talked about exposing Objective-C to JavaScript. What about the other way around, where you want to get access to anything that's already in JavaScript from Objective-C? You can do that using the WebScript object, and that's what encapsulates every JavaScript object and function. If you do an evaluate web script, this will return you a web script object of the result, which could be a string, it could be an object. And every WebView has a Windows script object, and every web frame has a document DOM object, which is under the hoods a web script object, which maps to the JavaScript class.
So here's an example. I get the Windows script object from the web view, and I call evaluateWebScript. And this just treats the string just like it was any other script that I might have quick access to. If it's a function that takes no parameters, this is fine to use.
But really, the preferred way to do any JavaScript access is using the new, which is available in Tiger and Panther, callWebScript method with arguments. And this is quick and very direct. It doesn't have to parse the script. It just calls the method directly. So you want to get the Windows script object.
You can ask for another object. In this case, I'm getting the MyScript. So I'm going to get my sprite off of the Windows script object. And then I can set up my arguments. And the arguments are passed in as an NSArray in the order that JavaScript expects it.
Then you just call web script method, and you pass in the name, no curly braces or parentheses or anything, just the name of the function that you're calling on that object, and any arguments you want to pass in. You can pass in nil if you don't have any arguments. And that's the fastest and most direct way to access JavaScript from Objective-C. So that's the web scripting interface. Now I'm going to hand it over-- actually, I'm going to talk to you what's new in Leopard.
We've added a lot of cool new things in Leopard. If you've attended any of the previous sessions, such as Safari for Web Content Developers, you've heard what we've added to the engine. The same sort of applies to the Cocoa APIs. One new thing we've added is the ability to have transparent web views.
This is a popular request where you want content to be able to see through the content, or dashboard is already using this for the rounded corners, being able to have drop shadows that blend in with the background, and poking holes through your window. You can now do that with Web Kit using the setDrawsBackground method, and that will prevent Web Kit from drawing any background if the page doesn't specify one.
You can also now access node layout metrics of the DOM objects. We added this for the Web Inspector primarily. It's really good for debugging, but it's also handy if you need to show anything that's overlaid the WebView, such as a child window. That's how we do the red outline in the Web Inspector.
It's a child window that draws over top of the WebView, and the correct location that we get from the DOM node about is layout. And that's very useful if you need to do any matching of native content with your WebView. Tim Hatcher, Tim Omernick You can also now get access to the match CSS rules, and this is handy if any of you have ever tried to Get access to CSS rules through the style sheets and digging through each one that you might have specified in a style sheet. You really don't know which ones apply to an element. Now you can pass an element and find out a list of rules that actually apply, and you can then modify those rules and manipulate them as you would expect.
Like I showed you earlier, we now have Objective-C DOM-less event listeners. So you can register yourself as a native Objective-C class to listen for click events, double click events, mouse move, mouse drag. That's all happening inside the Objective-C or inside the Web Kit DOM. So you don't have to drop down into JavaScript like you might have had to do before just to get those basic events. you can now do that with native code and objective C.
XPath Expressions. You can now evaluate XPath in the Objective-C DOM on a document. So you can ask for, with an expression, get a list of nodes that match in that document. And that's very useful if you need access to multiple nodes. I talked about get element by ID. That's really useful if you're only getting access to one node. But if you have a list of nodes in a structured document that you need access to, you should use an XPath. and you can get to those very quick.
We've also beefed up our DOM level 3 support. We've added a lot of new properties based on the W3C spec. There's some that we haven't gotten around to, but most of those are now available through Objective-C and JavaScript. So I want to give you a demo of transparent web views.
Using my same chat application, I'll bring up : I'm going to start the demo again. And like I had before, just a normal chat message. I also added some JavaScript that brings up a handy little preference for the user to change the opacity of the WebView. So now my WebView is poking through to the background. So, I have some objectives, just like everything else.
I have some opaque areas, which is the chat message, but the background is poking through. So, how did I do that? I'm using a new property that we've added that is proprietary to WebKit, so it has the WebKit prefix. And it's a background composite mode, similar to all the composite modes you're used to in Quartz. You can specify them for the background image to draw with.
And in this case, I'm using clear and specifying just any ping, and it's going to clear everything in the backing store. And to do that, you need to set up your window to be non-opaque. So I did that in Awake from Nib, if some of you noticed that earlier.
That's fine. I'm making a clear hole in the background. What about the color that I'm changing on top of that? I made a fixed position element, and I'm not going to go into the details of fixed position elements, but it just sits there and doesn't change when scrolled. So it stays in that position over top of everything, and it's actually a z-index order behind everything. It just has an RGBA value, and I'm starting it out as no opacity. But my slider takes care of that.
And I have some JavaScript that gets called every time the slider is called. And I'm using the same APIs I talked about in the web scripting interface to actually call back into my Objective-C. I could easily do this style change of changing the color directly in Objective-C, but I'm actually calling it back into the Objective-C class to change the color.
The call is actually in here. The JavaScript is irrelevant, so ignore that previous. So, I'm actually calling into my chat controller and telling it to adjust opacity. And you can see I'm using the web scripting APIs to expose Adjust Opacity, changing the Adjust Opacity name to get rid of the trailing underscore that comes from that colon.
And the adjust opacity method simply gets the background element by ID, makes a new CSS value for the background color, but it takes the opacity and makes a new value based on the slider value. And I simply set the property for the background color on the background element style property. So that's how you get the effect of poking and seeing through the web view. So back to slides. Now I'm going to hand it over to Tim Omernick, and he's going to talk to you about what's new in our plug-in APIs.
Thank you, Tim. Can you guys hear me OK? So I'm Tim Omernick, and I'd like to talk to you for a few minutes about plug-in APIs and what's new in Leopard. I'm not going to talk too much about how to create a plug-in. We've gone over that in previous WWDC sessions. But I'd like to give a little bit of an overview, in case you don't really know anything about plug-ins.
So what can a plug-in do? The right question is, what can't Web Kit do? Web Kit's very good at displaying HTML, parsing CSS, and running JavaScript. It does those things very, very well. But it can't really do much more. And that's where plug-ins come in. If you need to extend your Web Kit applications' rendering capabilities, or even provide capabilities that aren't graphical in nature, you might consider making a plug-in.
So some examples of plug-ins. We have QuickTime to handle QuickTime content. There's a Quartz Composer plug-in to handle Quartz Composer. There's various PDF plug-ins, both Apple and third party. You can also write a plug-in to handle your own content type. Plug-ins don't just work in Web Kit, they also work in Firefox and other browsers, as well as in the dashboard environment.
So Web Kit understands two kinds of plug-ins. There are Web Kit plug-ins, which are great, because they're Cocoa-based. They're designed with Web Kit in mind. A Web Kit plug-in is just an NS view. You can use all of the same technologies that you're familiar with-- App Kit and Core Graphics-- to do your drawing, et cetera.
The one caveat, though, is that Web Kit plug-ins only work in Web Kit-based applications and in Dashboard. So if you need your plug-in to work in Firefox or Opera or another browser, this is not really an option. We also support Netscape plug-ins. These are the cross-browser plug-ins. These work in all browsers. These are a little bit harder to create because they're based on Carbon.
Again, what kind of plug-in should I create? Well, if I'm making a Web Kit application, and I just need one specific piece of functionality that Web Kit does not provide by default, I would use a Web Kit plug-in. Or if you're making a dashboard widget, that is just a fantastic use for a Web Kit plug-in.
Again, if your plug-in needs to run in any browser, Netscape plug-ins are really your only option. OK, creating a Web Kit plug-in. I'm not going to get into this too much. I wanted to let you know that in Leopard, we have an Xcode project template. So now you can go to New Project and select Web Kit plug-in. Easy as that.
and I wanted to remind you about two pieces of sample code that we have, Web Kit Movie Plugin and Netscape Movie Plugin. So I'd like to give you a demo of a plug-in. This is an interesting Web Kit plug-in. It's interesting to me because-- could we switch to the demo? Thanks. This is interesting to me because most people think of plug-ins as these rectangular regions that draw something on a web page. And this isn't that kind of plug-in.
I just want to make sure my volume is OK. So here I have a web page with some input fields and some text and stuff. Looks pretty basic. I sure like being inside this fancy computer. So if you're familiar with web development, you might know that that's not something you can normally do on a web page. You can't normally just speak text. Another example, I have a little mouse-over effect. Wowee. Wowee.
And this is kind of an interesting application for this technology. This is sort of like an auditory tool tip. When I click in this text field, it's going to give me spoken instructions about what to do with that field. You can imagine this being useful for people who aren't very computer savvy, or perhaps people who are sight impaired.
Please type in the name of your favorite carbonated beverage. OK. So how does that work? Let's look at our HTML here. Pretty simple. We have an embed here, where we put the plug-in in the page. Make note of the fact that we give it a unique ID, so that we can reference it later.
And then we have our various examples. You'll notice in my CSS here, my speech plug-in has a width and height of zero. That's kind of weird for a plug-in. That basically means that the plug-in isn't going to draw. It's zero-sized. The plug-in is intended to just sit in the page and provide a service to the rest of the page. And here in my JavaScript, I have to find two functions. One of them takes some text, gets the plug-in element by its ID, and then calls a function on it.
So the code is pretty simple. Here we just create a plug-in view. Start up the speech synthesizer. This is all just built-in Cocoa stuff. Release the speech synthesizer. Here's my startSpeakingString function, the Objective-C version of it. It just passes the string off to the speech synthesizer. You'll see here, these might look familiar from Tim's presentation a few minutes ago. This is how I expose the start speaking string and stop speaking string methods to JavaScript.
And that's it. Can we switch back to slides? So that was a Web Kit plug-in. That just gives you an idea of an interesting way that you can use plug-ins in your application that you might not have thought of before. So. Let's talk about Netscape plug-ins. This is an old API that was designed to support plug-ins that can run in any browser. It's a fine API. It works great. All the major plug-ins are using this today. It has some problems, though. It's a little bit outdated. It was designed a really, really, really long time ago. And the state of the Mac has changed since this API was first developed.
So I've been talking to some plug-in developers who are pretty frustrated with the situation. And here's what they tell me they want to be able to do with their Netscape plug-ins. You might have heard about our 64-bit announcement. All of our frameworks in Leopard are now 64-bit. This means that in theory you can create a 64-bit plug-in.
The problem with that though is of course there is no 64-bit version of Quick Draw. So if you want to create a 64-bit plug-in, you're going to need an alternative API if you want to get anything on screen or even loaded at all. If you want to draw with any sort of performance, this is a little bit exaggerated.
But I wanted to get the point across that if you're using Quick Draw to draw, that's fine. It's not going anywhere for now, but we're not improving it. We're not making Quick Draw any better. So if you really want that high-performance drawing, Quick Draw is not really the answer.
Developers want interesting effects like shadows, transparency, cool sort of rotation scaling effects. And that's kind of a biggie, 3D. These are all very, very hard to do with Quick Draw. So we happen to have a couple of technologies available for you. We are bringing Core Graphics and OpenGL support down into the Netscape Plugin API so that you can actually use Core Graphics and OpenGL to draw your plug-in content.
So how do you actually use this new API? Well, we've proposed an extension to the existing Netscape plugin API called Plugin Drawing Models. And the way it works is when your plugin is initialized, it tells the browser which kind of graphics context it would like to use, whether it's Core Graphics, OpenGL, or Quick Draw.
To actually use it in your plug-in, you have to pick the drawing model in your NPP new function. This is sort of your plug-in init function. The basic process is that you ask the browser if it supports Core Graphics or whatever drawing model you're interested in, in this case Core Graphics. If the browser does not support the drawing models that you're interested in, you can return an error so that your plug-in doesn't load. If the browser does support the plug-in drawing model that you're interested in, you can use set value to set it. Simple as that.
Okay, so what does that actually do? Well, if you've written a Netscape plug-in before, you might be familiar with this NP port structure. This is used to indicate to the plug-in which graphics context, which Quick Draw port your plug-in should draw into, as well as where in the port it should draw.
In a Quick Draw-less environment, that's obviously not a very appropriate structure, so we've introduced a new type, NP-CG context. So the way you actually use that is when you're handling your update event, you would just assume that the NP Windows port structure is actually an NP CG context instead of an NP port.
So drawing with OpenGL is very similar. You just ask if the browser supports it. You set it. In this case, there's another type, npglcontext, that gives you access to a cglcontext and the window. And in your handle update event, the browser actually sets up the port before it calls into your plug-in. So pretty much you can just start making GL calls, and everything will just show up.
So OpenGL windowed versus windowless. OpenGL is really interesting because there are sort of two uses for it. You can use OpenGL to generate these really, really awesome fancy effects, you know, with shaders and all sorts of interesting options and stuff. Or you can use OpenGL to get really, really fast graphics, get hardware-accelerated litting and such.
So we actually let you pick which mode of operation you want. By default, plug-ins are windowed, meaning that they're hardware accelerated, and they can't layer inside the page. They just basically float above the browser. But this is by far the more high performance path, so this is on by default. : OpenGL plug-ins can optionally be windowless, meaning that they're rendered off-screen. This eliminates your hardware acceleration capabilities, but the benefit is that you get transparency and layering and interesting effects.
The way you actually set that, this is not a new API, it's just something that we never really implemented before. But you use NPP set value, or NPN set value with the plugin window bool variable. Set it to false if you want windowless mode. That's not actually a typo. I'm casting false to avoid pointer. I know, it's really weird. That's just how the Netscape plugin API works.
So if you want to learn more about these drawing models, we've updated our NP API header. You can find that in the Web Kit framework. We also have two pieces of sample code that we're going to make available to you. They're not online yet, but they will be shortly. Netscape Core Graphics Plugin and Netscape OpenGL Plugin. I'm actually going to give you a demo of the OpenGL plugin.
[Transcript missing]
So you can see my cheesy 3D rotating cube. It's all lit with GL lights and all that. This is actually a windowless plug-in, meaning that it's being software rendered. And you can see that the background is transparent, so it's layering over the text correctly.
I've set this HTML up such that the text is below the plug-in, and the plug-in is below this Safari icon. And when I scroll, the cube is just going to stay still just to show you how it can layer with other page elements. This is something that you just couldn't do before.
Okay. The code, actually, I guess I can show you. It's pretty similar to what you saw up on the slides. Here in my NPP new, whoops. I ask if the browser supports OpenGL, and then I pick the OpenGL drawing model. This plug-in can actually run in both windowed and windowless mode.
So you can see us setting the window variable there. And then in my handle update event, You can see that I just go straight into making OpenGL calls. I set up my GL, set up the lights, clear the background, all of that. That's a really inefficient way to draw a cube, I One more thing I wanted to show you. If I go in my HTML here, And change this, this is my reference to my plug-in and my HTML. I can just get rid of this wmod=transparent.
That's how my plug-in switches between windowed and windowless mode. And then when I go and actually open this in Safari, You can see that it's switched to windowed mode, and it floats above everything else. But this is actually hardware accelerated, so you're getting a much higher frame rate.
Can I switch back to slides? Okay, so that was plug-in drawing models, and I hope that you're inspired to take advantage of those APIs now in Leopard. There's one more API I wanted to talk about. This is a pretty exciting one. It's pretty cool. Plug-ins now in Leopard are able to access and manipulate their own DOM elements.
That sounds like techno mumbo jumbo. What does that actually mean? Well, a DOM or a plug-in can do really, really interesting things. It's no longer just this fixed rectangle on a page that's told to render in some location and look some way. It can actually fully integrate with the rest of its document.
It can do really interesting things, like move itself or resize itself. It can access its own CSS properties, set its own CSS properties, like opacity and borders and outlines and such. You can do things like making the text in the plug-in. If your plugin draws text, you can make it match the text in the surrounding document.
The way you use this is we have a web-- when your plug-in is created, it's passed an arguments dictionary. This is for a Web Kit plug-in. One of the arguments that you get is a web plug-in containing element key. This is actually a DOM element that you can manipulate using the same APIs that Tim Hatcher talked about a few minutes ago.
We also have support for this API on the Netscape side. This uses the NP Object Runtime API. I'm not going to get into that now, but there's plenty of documentation available for that online. You can also see our NP Runtime header. The way you use it on the Netscape side is to just get the value for the plug-in element NP Object variable. So I wanted to show you a demo of that.
So this is a Web Kit plug-in. I'll show you my code first. It's pretty basic. You can see here in my plug-in view with arguments, I save the arguments that are passed to my plug-in. That'll be important later. I'm not going to get too much into how this thing draws or actually magnifies, does its thing. It's not too important.
It's not too relevant. What I wanted to show you, though, is this -- you know what? This is going to make a lot more sense if I just show you first. So here's my plug-in. You can see that I can click it and drag it around on the page.
So that's pretty cool. How does that actually work? How does the plug-in move itself around on the page? Well, you can see in my view's mouse-dragged method, I get that containing element, and I get its CSS style object. This is a really powerful object to have access to, because you can set things like top and left to move the plug-in around on the page. So you can see here that I get the property left from the style. Add the horizontal mouse movement, and then just set the value back on the property. And I do that again for the top. And that's really it. Next slide, please.
Okay, so that's all I wanted to talk to you about today. If you want more information about this session or plug-ins or Web Kit in general, you can talk to Mark Malone. He's our Internet Technologies Evangelist. If you want documentation, you can look on the WWDC site or just in general developer.apple.com.