How to write code that interacts with Netscape while extending its capabilities.
Andrew Taylor and Raymond GA Côté
In this article we present a short excursion into the Macintosh LiveConnect plug-in software development kit (SDK) for Netscape Navigator 3.0. We modify the sample applications provided in the SDK, connect a third-party graphics library from Snowbound Software, and point out a few pitfalls for the unwary. The final result is a plug-in that allows you to display PCX files on the Mac and perform the simple manipulations of rotating and resizing images.
Your First Plug-In
The Netscape plug-in SDK is available free of charge from the Netscape Web site at
http://home.netscape.com/comprod/development_partners/plugin_api/index.html
. It contains projects for Mac, Windows, and Unix machines.
The SDK is simple to use and quick to implement, but, unfortunately, it's the source of some maddeningly obscure problems. All the SDK sample projects were built using Metrowerks CodeWarrior release 9. We made all modifications to the
MacShell.cpp
file, which is one of the source files in the project.
Navigator presents data to a plug-in in one of two formats: stream and file. The
stream
data type allows the plug-in to operate on data as it's downloaded from the network. The
file
data type indicates that the plug-in wants to see the entire file before processing. The imaging library we use prefers to process com
plete files, so we'll concentrate on that method.
Modifying the MacTemplate project code is simple and obvious. The steps are outlined below.
First, declare an image-handle variable (
fImgHandle
) for storing the decompressed image. Second, initialize this new variable by setting it to -1 during the call to
NPP_New
. Third, clean up the memory by releasing any allocated memory during
NPP_Destroy
.
In the fourth step, add the following line to
NPP_NewStream
to inform Navigator you want a file, not a stream:
*stype = NP_ASFILEONLY; // we are file-oriented
Step five is where all the difficult work comes in. In the call
NPP_StreamAsFile
, add the lines shown in the first section of the table
"Code Gallery"
to decompress and display the image. When the Web page references a uniform resource locator (URL) on a remote Web page, Navigator first downloads the image into a temporary file and then hands you the name of the temp
orary file. Navigator automatically deletes this image file when it's no longer needed.
In the final step, change the
DoDraw
call to display the image. Navigator provides several things: a pointer to the graphics port for display, the origin within the port, and the height and width of the image. The Snowbound library scales the image to fit within that viewing area.
Then you build the project. The resulting shared library (for PowerPC) or code resource (for 680x0) is ready to test.
The plug-in resulting from the preceding six modifications displays a PCX image directly in a Web page. But the image may look rather strange. The reason for this took a little while for us to discover and was the subject of our first lesson about plug-ins.
Mixed Lessons
Lesson one:
Never trust the state of the world. Implementing a simple image-decompression/image-display plug-in took three calls and just minutes. Unfortunately, the displayed colors bore little resemb
lance to the way that the Snowbound library usually displays the image.
It turns out that Netscape changes the window's foreground and background colors. Adding a call to save the
GrafPort
settings, forcing them to known values, and then restoring the original settings when done solves this problem.
Lesson Two:
Use minimal code to paint. Your plug-in might receive an update event multiple times when you think one would be sufficient. Just make sure you don't do a lot of calculations in your paint routine. Simply updating the display from an off-screen bit map is probably optimal.
Lesson Three:
When debugging, debug the right code. Debugging a plug-in (in our case, a PowerPC plug-in) is fairly simple. Just follow the steps below.
- Quit Netscape Navigator. This is
very
important. You can spend a remarkable amount of time debugging the wrong version of the plug-in because Navigator cached the previous version.
- Drag an alias of your pl
ug-in into the Netscape Plug-Ins directory.
- Set up your debugger to break on the
NPP_Initialize
call.
- Launch Navigator and open a Hypertext Markup Language (HTML) page, which exercises your plug-in.
JavaScript Makes It Live
Adding a new display ability to Navigator is useful, but the combined power of JavaScript, Java, and plug-ins provides the ability to also interact with the plug-in directly on the Web page.
We previously attempted to build a plug-in for Navigator 2.0 that presented the user with buttons and scroll bars for manipulating the displayed image. It worked just fine -- until we scrolled through the browser window. The resulting screen paint was very ugly. Buttons would lose their position, and the scroll pane was never sure where to update itself on the screen.
The solution is to build the direct-manipulation elements from standard HTML elements and use JavaScript to communicate with your plug-in. Go back to the SDK to modify another sam
ple project. This time it's the
CharFlipper
sample code.
Communication between a Web-page user-interface element and a plug-in requires three levels: the JavaScript User Interface component, Java
glue
, and the plug-in itself. This chain of events is illustrated in the figure
"Using JavaScript to Operate a Plug-In"
. Each level requires a method (i.e., a function) with the same name. In our example, it's Rotate. This method rotates the displayed image 90 degrees clockwise each time it's called.
We can start at the user-interface level by attaching a JavaScript statement to a simple button that says "Rotate." The JavaScript statement is as follows:
onclick="document.ImageViewer.Rotate();"
JavaScript cannot directly call the plug-in. It must use a simple Java class as its glue. For that purpose, we created a Java class, called
ImageViewer.class
, which is placed in the Netscape plug-ins folder. This class contains a method definition as f
ollows:
public native void Rotate();
It's that simple. The JavaScript calls the method in the Java class, which is defined as native. Java knows to seek out a plug-in with the same name as this class and then call the proper C++ method.
Now we call the C++ plug-in ImageViewer. The Rotate method that Java calls is declared as follows:
void native_ImageViewer_Rotate
( JRIEnv* env, struct ImageViewer * self );
The naming convention can get a little long, but it's pretty clear. The
env
and
self
parameters are used to obtain access to the object instance. You need to do a standard invocation first, as shown in the second section of the table
"Code Gallery."
The interplay of HTML, JavaScript, and custom plug-ins provides a powerful combination of cross-platform presentation and native compiled-code speed. Although Navigator is still a work in progress, version 3.0 provides a strong base upon which useful applications can be
built.
Section 1: Display a graphic
// The following line calls the Snowbound library to do
// all the decompression work.
This->fImgHandle = IMG_decompress_bitmap((char *)fname);
// Display the image.
if( StartDraw(This->fWindow))
{
DoDraw(this);
EndDraw(This->fWindow);
}
Section 2: Call the Rotate method
// get plug-in structure back for this instance.
NPP instance = (NPP)self->GetPeer(env);
// retrieve pointer to the actual instance.
ImageViewer *iView = (ImageViewer *)instance->pData;
// Now able to use object methods and variables.
// Invoke the rotate method.
iView->Rotate();
illustration_link (29 Kbytes)

How events flow from JavaScript to a Netscape plug-in.
Andrew Taylor and Raymond GA Côté develop custom cross-platform applications at Appropriate Solutions, Inc. (Peterborough, NH). You can contact them at
aetaylor@AppropriateSolutions.com
and
rgacote@AppropriateSolutions.com
, respectively. The Snowbound imaging library can be found at
http://www.snowbnd.com
.