Creating Plug-ins with the Netscape API

Netscape-style plug-ins are written using a cross-platform C API, and, provided that you are building in Mach-O form, can be developed and debugged with Xcode. These plug-ins are compatible with a wide range of web browsers.

The original Netscape plug-in architecture was integrated into Netscape 2.0 in 1996. Since then, the API has been adopted by most common web browsers, including Safari. It has built-in support for onscreen drawing, various types of event handling, and networking functions.

In addition to the core plug-in functionality, Apple has extended the capabilities of the Netscape-style plug-ins. Starting with the WebKit framework bundled with Safari 1.3 (on OS X version 10.3) or Safari 2.0 (on OS X version 10.4), the Netscape-style plug-ins can also perform scripting functions.

The Netscape-style plug-in scripting environment allows plug-ins to access scripting languages such as JavaScript (including accessing script elements such as a web page’s Document Object Model). It also allows scripting languages to access and control elements of the plug-in.

In OS X v10.5 and earlier, Netscape-style plug-ins can be compiled in OS X into either the Mach-O or PEF (CFM) binary format (although CFM is PowerPC-only). Beginning in OS X v10.6, Netscape-style plug-ins should be updated to use a 64-bit binary to work with 64-bit instances of Safari or other WebKit clients. To do this, they must be built as 32/64-bit multi-architecture binaries using the Mach-O file format.

Though the API supports both formats, OS X natively supports the Mach-O style, and you will find that your plug-in will run much faster if compiled as a Mach-O binary. In the future, WebKit will continue to support Netscape plug-ins built with the Mach-O format; no such assurance can be given for plug-ins compiled in the PEF (CFM) format. You can also develop and debug Mach-O plug-ins in Xcode, but not PEF plug-ins. Once compiled, the plug-ins can be installed and used in most web browsers.

Using Plug-in Scripting

The scripting capabilities of Netscape-style plug-ins are provided by extensions onto the original plug-in specification. They allow a browser (through JavaScript) to access and control elements of the plug-in and its content, and allow the plug-in to access the enclosing web page and its content through the plug-in script interface.

When a plug-in is loaded, the browser calls the NPP_GetValue callback in your plug-in, which returns a retained NPObject structure that represent your plug-in. This NPObject structure contains an pointer to an NPClass structure. The NPClass structure contains a series of callbacks that define the interface between the plug-in and the scripting environment. The NPObject instance represents an instance of that plug-in that can then be used by the scripting environment.

If you want your plug-in to be scriptable, you need to return the appropriate retained NPObject by reference in your NPP_GetValue callback function.

A good demonstration of accessing plug-ins from JavaScript, as well as all the other concepts in creating a Netscape plug-in, can be found in the Examples folder of the WebKit source code. See http://www.webkit.org/ to learn how to download the WebKit source code.

Core Graphics and Core Animation Drawing Models

Safari 4.0 provides two new drawing models: Core Graphics (Quartz 2D) and Core Animation (only in OS X v10.5 and later). These drawing modes are strongly recommended going forwards, and if you move your plug-in to contain a 64-bit slice, that slice must use these drawing models. (See “Transitioning a Netscape-Style Plug-in to 64-bit” for more information.)

Most of the effort in using these drawing models comes from learning Core Graphics and Core Animation themselves. To learn about Core Graphics, read Quartz 2D Programming Guide. To learn about Core Animation, read Core Animation Programming Guide.

Once you understand how to draw things using Core Graphics or Core Animation, you can enable these drawing models in your NPP_New function as follows:

After you have done these two things, the browser fills the window field of the NPWindow structure with an NP_CGContext structure. This structure contains two fields, context and window, which are defined as follows:

typedef struct NP_CGContext
{
    CGContextRef context;
    WindowRef window;
} NP_CGContext;

The context value is a Core Graphics drawing context suitable for Quartz 2D drawing. For more information on how to use this context, read Quartz 2D Programming Guide. The window is a reference to an NSWindow object.

To obtain the bounds for your plug-in’s drawing region, do the following in your NPP_SetWindow callback:

NPError setwindow_cb(NPP instance, NPWindow* npw) {
    ...
 
    NP_CGContext *npcontext = npw.window;
    CGContextRef context = npcontext.context;
    CGRect boundingBox = CGContextGetClipBoundingBox(context);
 
    ...

The Core Animation model is similar, but reversed. If you set you set NPNVpluginDrawingModel to NPDrawingModelCoreAnimation, your NPN_GetValue callback must provide a retained Core Animation layer to the browser when it queries the NPPVpluginCoreAnimationLayer variable.

As with the Core graphics model, you can find out if the browser supports the Core Animation drawing model by checking the value of the NPNVsupportsCoreAnimationBool variable. For example:

NPBool supportsCA = false;
NPError error = browser->getvalue(instance,
    NPNVsupportsCoreAnimationBool,
    &supportsCA);

Out-of-Process Plug-Ins

Beginning in OS X v10.6, on 64-bit-capable computers, Netscape-style plug-ins execute in an out-of-process fashion. This means that each Netscape-style plug-in gets its own process separate from the application process. This design applies to all Netscape-style plug-ins. It does not apply to WebKit plug-ins, nor at present to WebKit-based applications when running in 32-bit mode.

Out-of-process execution is used for several reasons:

For your plug-in to work correctly in this new environment, you may need to make some changes to your code, depending on how it interacts with the rest of the system beyond the browser.

Transitioning a Netscape-Style Plug-in to 64-bit

Beginning in Snow Leopard, Safari is moving to a 64-bit process. This section describes how to adapt a Netscape-style plug-in so that it works when compiled as a 64-bit plug-in. It describes only the changes specific to Netscape-style plug-ins, providing links to other documents for general 64-bit porting information.

Before you begin, do the following:

Once you have read these documents, you need to make a few additional changes specific to Netscape-style plug-ins (at least when compiling 64-bit versions of your plug-in). These changes are as follows:

Once you have accounted for these differences, you should be ready to compile your plug-in with a 64-bit slice. For more information on compiling code for 64-bit, fixing truncation bugs, and various other relevant topics, read 64-Bit Transition Guide for Cocoa and 64-Bit Transition Guide.