Extending Netscape’s ability to handle additional file formats.
Plug-ins are a powerful mechanism for extending the capabilities of Netscape’s web browser. Using plug-ins, the browser can display files in formats that were not even conceived of when the browser was developed, such as multimedia files embedded within larger web pages. This allows web pages to be designed with maximum visual impact. Like any powerful technology, plug-ins can easily be misunderstood or misused. This article will explore when Netscape plug-ins might be appropriate to use, explain how to install and remove plug-ins, suggest where to locate useful plug-ins, and provide insight into implementing your own plug-ins.
Plug-ins vs. Helper applications
It might be useful to compare and contrast plug-ins with helper applications. Plug-ins and helper applications share many features and may be used interchangeably in many circumstances. Helper applications are older and may be more familiar to users than plug-ins. Netscape has supported helper applications since version 1.0 of their browser software, but plug-in support did not show up until version 2.0 (version 3.0 for UNIX).
Both helper applications and plug-ins are supplementary software used by web browsers to handle specific file formats. Helper applications can be run independently of the web browser. Plug-ins, however, are integrated into the browser and can be run only within a browser. Potential helper applications may already be installed on your system. Some very useful helper applications, such as xv, were developed even before web browsers became popular.
Helper applications, being independent of the browser, must create their own window for a user interface. Plug-ins may use the window provided by the browser. Since they share the browser window, they can be used to display files that are embedded within larger HTML files. Helper applications cannot display embedded files. Plug-ins can have access to file contents while the file is being downloaded by the browser. Such plug-ins are called “streaming” plug-ins. Helper applications are “launched” only after the file is fully downloaded.
Review of MIME
The MIME (multi-purpose Internet mail extensions) protocol, described in RFC-1521, allows applications to exchange different types of files on the Internet. A text header identifies the data format of the message body. Web browsers use MIME information to categorize files before displaying them. For example, if the MIME header indicates the body is of type “image/gif”, the browser will display the message body as a GIF (Graphics Interchange Format) file. If no MIME header is available, the browser assigns a MIME type to the file based on the file’s extension. Once the MIME type of the file has been determined, the browser searches its internal tables for the plug-in or helper application assigned to that MIME type.
When to Use Plug-ins
As a web surfer, you may encounter HTML pages that have other files embedded within them. Without an appropriate plug-in, your browser will not be able to display the embedded file. It might seem impolite for a web-page designer to create a page you cannot display without specialized software, but there are some reasonable excuses for such behavior. For example, certain non-proprietary MIME types are in common use on the Internet, and are supported by Netscape on the Mac OS and Windows, but not UNIX. UNIX users must install a plug-in for such MIME types. One example of this type of file is MIDI (musical instrument digital interface); these are often embedded within web pages to provide background music.
As a web designer, you may want to use a newly developed multimedia file format on your web page. The current MIME type may have been developed too recently to be supported by existing browsers. The MIME protocol is designed to be extensible. Third parties are constantly developing new MIME types with specialized functionality. Examples of such MIME types include document rendering (application/pdf), portable graphics (image/png), vector graphics (application/shockwave-flash) or streaming audio (audio/pn-realaudio-plugin). Often these MIME types are developed in the hope of selling authoring software. Polite third parties provide free plug-ins for as many platforms as possible. Unfortunately, UNIX support is often the first to be sacrificed.
It may be tempting to invent new MIME types, rather than using existing functionally equivalent MIME types, or to embed specialized file types on your web page, such as Microsoft PowerPoint files. However, your viewers might not have an appropriate plug-in or may be unable or unwilling to locate and install one. Your carefully designed web page may have dull gray rectangles where you expect flashy graphics. It is generally a good idea to use only the most popular Internet MIME types on your web pages. If your needs can be met only by using a more specialized MIME type, it is polite to first check for plug-in availability or even supply the necessary plug-ins yourself.
Where to Get Plug-ins
Many sources are available for Netscape plug-ins. Netscape maintains a web site of plug-ins organized by functionality or platform (see Resources 1 and 2). Netscape equips their browsers with a special plug-in called the “Default Plugin”, which is invoked when an unregistered MIME type is encountered. With user approval, the default plug-in will search the Netscape web site for appropriate plug-ins.
The Netscape web site is not the only source of plug-ins, although it may be the most convenient. Traditional sources such as Usenet newsgroups, WWW searches and even word of mouth can turn up useful plug-ins.
Be aware, however, that the same precautions should be used when downloading plug-ins as when downloading any other software. Although plug-ins are not full-fledged application programs, they can inflict just as much damage, intentionally or not. Unlike helper applications, plug-ins can cause the browser to leak memory, become unresponsive or even dump core. If the source code is available, you could inspect the code before compiling the plug-in yourself. Otherwise, you will have to trust the source of the plug-ins. Just because a plug-in is registered with Netscape’s web page does not mean that Netscape provides any sort of warranty about the behavior of the plug-in.
How to Install and Remove Plug-ins
Plug-ins are dynamic code modules, native to the platform on which the Netscape client runs. For example, Windows plug-ins are DLLs and UNIX plug-ins are shared object libraries. When Netscape Navigator starts up, it checks for plug-in modules in certain directory trees. Each plug-in candidate in the directory tree is loaded, its capabilities determined using the plug-in API (application program interface), then unloaded. Internal tables assign MIME types to particular plug-ins. Later, if the browser encounters a MIME type that requires plug-in support, the plug-in is reloaded and remains loaded until the page is closed. The list of registered plug-ins can be viewed using the “Help/About Plug-ins” menu. Removing a plug-in is as simple as deleting the shared library.
The README file which comes with Netscape Communicator for UNIX explains the algorithm for generating the plug-in list:
if($NPX_PLUGIN_PATH environment variable is set)<\n> Look at $NPX_PLUGIN_PATH, where $NPX_PLUGIN_PATH is a colon-delimited list of directories. else Look at all the following directories in order, overriding previous entries in case of duplicates: /usr/local/lib/netscape/plugins $MOZILLA_HOME/plugins $HOME/.netscape/plugins
The algorithm for Netscape 3.0 is even simpler. Only the directories /usr/local/lib/netscape/plugins and $HOME/.netscape/plugins are checked.
Only one plug-in or helper application can be assigned to each MIME type. These assignments are stored in the files $HOME/.mime.types and $HOME/.mailcap where they can be used by other applications. A dialog window allows users to resolve conflicts. For Netscape 3.0, the dialog is under the “Helpers” tab of the “Options/General Preferences” pull-down menu. For Netscape 4.0, the dialog is available via the “Edit/Preferences/Navigator/Applications” menu option. This menu also allows the user to associate file extensions with MIME types. Normally, the plug-in associates file extensions with MIME types when the plug-in is assigned to the MIME type.
Creating Plug-ins
You might have an idea for a great new Internet file format, but are wondering how to get Netscape to recognize it. You could be a web surfer whose favorite web site uses a file format unrecognized by Netscape or any of the available plug-ins. Or, you may just want to understand more about how your web browser works. In any case, the next few sections will briefly describe the process of designing and implementing your own plug-in.
First, a reminder about helper applications. If the file is not embedded within an HTML file, a helper application could also be used to display it. Helper applications are developed using traditional means, do not need to adhere to any special API, and do not require special debugging techniques. Even if your ultimate goal is a plug-in, it might be more efficient to first implement a helper application, then convert the helper application to a plug-in.
Once you have decided to build a plug-in, you will want to download Netscape’s plug-in SDK (software development kit) (see Resources 3). The plug-in SDK includes documentation, example code and even a template plug-in, written in C, complete with Makefile. The SDK documentation includes a complete reference manual for the plug-in API, and some general guidelines for plug-in design. Rather than duplicate that information here, I will explore how to use the API most effectively.
The Netscape SDK is designed to facilitate cross-platform development. The SDK allows developers to use a single source tree for UNIX, Windows and Mac OS plug-ins. However, there are significant hurdles for the cross-platform plug-in developer. Different GUI standards, OS standards and device interfaces must be considered. Even the plug-in file format varies by platform. For example,Windows plug-ins must have names beginning with “np” and provide descriptive information via a version resource, rather than the API. I will skirt around the thorny issue of cross-platform development by focusing on UNIX-only plug-in development.
The API
The plug-in API consists of two sets of functions. The first set, where the names begin with “NPP_”, are functions that the plug-in must implement. These functions will be called by the browser as it downloads the file. The second set, with names beginning with “NPN_”, are services which the plug-in may ask the browser to provide, such as allocating and freeing memory, reading and writing URLs, providing version information and writing messages to the browser status field.
There are more than a dozen “NPP_” functions. The thought of implementing such a large set of complex functions may seem scary. To demystify the API, these functions can be broken down into a few general categories. There are functions that allow the plug-in to describe its capabilities (NPP_GetMIMEDescription, NPP_GetValue), initialize and finalize data structures (NPP_Initialize, NPP_Shutdown, NPP_New, NPP_Destroy), write into a graphics area (NPP_SetWindow) and receive data (NPP_NewStream, NPP_Write, NPP_WriteReady, NPP_StreamAsFile, NPP_DestroyStream). There are also functions that allow the plug-in to enable LiveConnect (NPP_GetJavaClass) and to describe its graphics area to a printer (NPP_Print).
UNIX plug-ins must implement NPP_GetMIMEDescription. This function returns a semicolonseparated-list of MIME descriptions. Each MIME description includes the MIME type, the file extensions associated with that MIME type, and a brief description of the MIME type. NPP_GetValue returns the name of the plug-in, as well as a detailed description of the plug-in.
NPP_Initialize and NPP_Shutdown are called just after the plug-in is loaded and just before the plug-in is unloaded, respectively. These functions give the plug-in the opportunity to allocate and initialize global data structures, then free any allocated resources when they are no longer needed.
NPP_New and NPP_Destroy are called to create or destroy a particular instance of the plug-in player. More than one embedded file may have the same MIME type on a single HTML page. The plug-in may need to maintain separate data structures for each instance. When a plug-in instance is created, the browser provides environment information, such as whether the plug-in is embedded or full page, and whether there are any special directives within the HTML <EMBED> tag. However, the browser will not provide a graphics area or the file contents to the plug-in instance until after the instance has been successfully created.
NPP_SetWindow provides the plug-in with a graphics area to draw in. UNIX plug-ins are provided with a Motif Drawing Area widget. The plug-in may draw directly into the graphics area using X Window System functions, or it may create new widgets, using the Drawing Area widget as the parent. Note that because of the two-phase widget deletion scheme of X, the plug-in must not be linked with any widget library. Otherwise, X may try to execute the second deletion phase after the plug-in (and the widget library) has been unloaded, resulting in a core dump. The plug-in must use only widget classes already linked into the browser. For Netscape, this means Motif widgets.
The browser uses the functions NPP_NewStream, NPP_Write, NPP_WriteReady, NPP_StreamAsFile, and NPP_DestroyStream to negotiate with the plug-in about data transfer mechanisms. The plug-in can elect to receive the data piecemeal, or the plug-in may ask the browser to collect all the data into a file before delivering it. If the data arrives piecemeal, the plug-in can set upper limits on size and rate for data transfer from the browser.
The function NPP_GetJavaClass allows the plug-in to enable LiveConnect. LiveConnect is a technique for plug-ins to interface with Java and JavaScript. LiveConnect allows JavaScript to control the execution of a plug-in. LiveConnect requires a special Java class to be loaded and executed. For many plug-ins, this may be unnecessary overhead.
The function NPP_Print allows the plug-in to describe itself, in a platform-specific manner, to a printer. For UNIX, this means writing PostScript to a file. Full-page plug-in instances are given a choice of whether they would like to handle all aspects of printing or whether the browser should handle most aspects. Embedded plug-in instances have no choice. The browser will query the user about print destination, page size and orientation, etc. The browser will then open a file and begin writing its own PostScript. When the plug-in instance is encountered, the function NPP_Print is called. The browser passes in parameters reminding the plug-in instance of its location on the page and providing the plug-in instance with a FILE pointer to add its PostScript. When NPP_Print returns, the browser continues to add PostScript to the file, then closes the file and sends it to the print destination.
If the plug-in does not add any PostScript, there will be a blank area in the plug-in’s location on the printed page. Plug-ins that display still graphics should probably implement this NPP_Print. Plug-ins that display animation or which play sound may choose not to implement NPP_Print. This function will be called in response to a user selecting either the “File/Print” or the “File/Save As” menu option, then selecting PostScript as the output format. Needless to say, this is not a trivial function to implement properly. Even the PDF plug-in from Adobe contains a flaw which causes a core dump when using the “File/Save As” menu option. It may be better to omit this feature, rather than implement it poorly.
Design Issues
The SDK documentation advises against “blocking” any API call. The browser will not be responsive to user input while the API calls are executing. Therefore, these functions should complete in a reasonably short period of time. If a plug-in needs to perform time-consuming processing, a number of techniques can be employed. The best technique to use depends on a number of factors, including the nature of the plug-in as well as personal preference.
One popular technique is for the plug-in to create a completely separate “companion process”. This solution can be quite robust. A catastrophic failure in the companion process will likely not affect the browser. However, elaborate interprocess communication mechanisms may be needed to provide synchronization between the browser and the companion process. This technique is most appropriate if the processing is only loosely connected to the browser. It is also often the easiest technique for converting a helper application into a plug-in.
Alternatively, the plug-in could use time-slices within the browser to accomplish its processing. The plug-in can use the NPP_WriteReady function to limit the data transfer rate from the browser. With the data rate limited, the plug-in can perform the processing within the NPP_Write function without degrading browser performance. For example, a streaming video plug-in might limit the data transfer rate to the frame rate. Each time the browser invokes the NPP_Write function, the plug-in would need to process only one frame’s worth of data before returning control to the browser. This technique is most appropriate for streaming plug-ins.
The X event processing loop can also provide processing time-slices. The X event processing loop acts much like the scheduler in a cooperative multitasking operating system. It can be commanded to perform small processing tasks during idle times, or after specific time intervals via the XtAppAddWorkProc and XtAppAddTimeOut functions, respectively. This technique is most appropriate for plug-ins with interactive graphics, especially animation.
Finally, the plug-in could create a separate, asynchronous thread within the process. Thread programming can be difficult. Many UNIX libraries, especially graphics libraries, are not thread-safe. The plug-in designer must use care to avoid reentrancy problems. This technique should be reserved for situations where none of the previous techniques can be used.
Plug-ins can be difficult to debug. The browser does not load the plug-in until just before executing the plug-in functions. This does not leave much opportunity for a debugger to set breakpoints. It may be necessary to resort to using printf. One technique for using a debugger is to insert an artificial delay in a convenient location, such as at the beginning of NPP_Initialize. The delay can give a debugger time to “attach” to the browser. Once the debugger is attached, breakpoints can be set within the plug-in.
Conclusion
Netscape plug-ins can enhance the web surfing experience. After all, it is much more fun to experience creative multimedia than it is to see dull gray rectangles. Linux plug-ins are available for many commonly used MIME types; some require compiling, others are available as shared libraries, simplifying installation. Implementing plug-ins for unsupported MIME types is well within the capabilities of an experienced Linux programmer and can be fun. The source code for the UNIX MIDI plug-in (UMP) is available on the UMP download page (see Resources 4). This source code can be used as a starting point for other plug-in projects. I glossed over cross-platform development, LiveConnect support and printing issues. For more information on these topics or any plug-in topic, feel free to contact me.