NPAPI:CoreGraphicsDrawing: Difference between revisions
Line 71: | Line 71: | ||
// Check if the browser supports the CoreGraphics drawing model | // Check if the browser supports the CoreGraphics drawing model | ||
NPBool supportsCoreGraphics = FALSE; | NPBool supportsCoreGraphics = FALSE; | ||
if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR || !supportsCoreGraphics) | if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR || | ||
!supportsCoreGraphics) | |||
return NPERR_INCOMPATIBLE_VERSION_ERROR; | return NPERR_INCOMPATIBLE_VERSION_ERROR; | ||
// Set the drawing model | // Set the drawing model |
Revision as of 22:14, 12 July 2006
NOT READY
This page is not ready for viewing yet - it is very much a work in progress as I attempt to format the proposal.
Overview
Part of what made Apple's transition from Mac OS 9 to Mac OS X so smooth was that we provided backward-compatible APIs, like QuickDraw, so developers did not need to rewrite their applications for the new platform. Unfortunately, this plan worked a little bit too well -- some apps, including Netscape plugins, were never updated to use the modern APIs!
The Netscape Plugin API is showing its age. It assumes that browsers and plugins use QuickDraw, and that QuickDraw is the only way to draw. On Mac OS X, however, QuickDraw is a second-class citizen. It is a pain for a modern Mac browser to host Netscape plugins, because it must create and maintain a QuickDraw port for the sole purpose of hosting legacy plugins.
This problem is about to get worse in two ways:
1) QuickDraw is deprecated, and has been for some time. While it is sticking around for a while longer, it will probably be removed in a future version of Mac OS X.
2) Many of Apple's frameworks and libraries are being updated for 64-bit. QuickDraw is not invited to the 64-bit party. There will be no 64-bit QuickDraw.
Our proposed solution is to change the Mac Netscape Plugin API (NPAPI) so that it is graphics-API agnostic. That is, plugins are free to use whatever drawing API they like, so long as the API is available on the system and is supported by the browser.
The bottom line: we want to make it very easy for developers to move their plugins from QuickDraw to CoreGraphics, while maintaining compatibility with QuickDraw-only browsers.
Excluding QuickDraw
Plugins and browsers that are compiled 64-bit must entirely exclude QuickDraw support, since there will be no 64-bit QuickDraw.
We are adding a #define to npapi.h to make this easier:
#if defined(XP_MACOSX) && defined(__LP64__) #define NP_NO_QUICKDRAW #endif
You'll see this #define used throughout this proposal.
The Drawing Model
We're introducing the concept of the "drawing model" for Mac plugins. When the plugin starts, it negotiates a drawing model with the browser. The drawing model determines the type of graphics context created by the browser for the plugin.
A plugin may call NPN_GetValue() with the following NPNVariables to query the browser for its supported drawing models:
#ifndef NP_NO_QUICKDRAW /* TRUE if the browser supports the QuickDraw drawing model */ NPNVsupportsQuickDrawBool = 2000 #endif /* TRUE if the browser supports the CoreGraphics drawing model */ NPNVsupportsCoreGraphicsBool = 2001
Once the plugin finds a supported drawing model, it calls NPN_SetValue() to tell the browser which drawing model it will use. We're adding a new NPNVariable for this:
NPNVpluginDrawingModel = 1000 /* The NPDrawingModel specified by the plugin */
The value for the NPNVpluginDrawingModel is an NPDrawingModel, a new enumeration we're adding:
#ifdef XP_MACOSX /* The drawing model for a Mac OS X plugin. These are the possible values * for the NPNVpluginDrawingModel variable. */ typedef enum { #ifndef NP_NO_QUICKDRAW NPDrawingModelQuickDraw = 0, #endif NPDrawingModelCoreGraphics = 1 } NPDrawingModel; #endif
If the browser does not support any of the plugin's drawing models, then the plugin should return an error from NPP_New() so that it is not started.
Here is an example of a CoreGraphics-only plugin negotiating the drawing model:
static NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode, int16 argc, char* argn[], char* argv[], NPSavedData* saved) { // Check if the browser supports the CoreGraphics drawing model NPBool supportsCoreGraphics = FALSE; if (browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) != NPERR_NO_ERROR || !supportsCoreGraphics) return NPERR_INCOMPATIBLE_VERSION_ERROR; // Set the drawing model if (browser->setvalue(instance, NPNVpluginDrawingModel, (void *)NPDrawingModelCoreGraphics) != NPERR_NO_ERROR) return NPERR_INCOMPATIBLE_VERSION_ERROR; return NPERR_NO_ERROR;
}
The QuickDraw drawing model
QuickDraw is the drawing model used by all plugins today. The QuickDraw drawing model uses all the existing Mac NPAPI data structures and conventions. QuickDraw is the default drawing model, used when a plugin does not negotiate a drawing model. It is also used when the plugin explicitly sets the drawing model to NPDrawingModelQuickDraw.
In 64-bit, the QuickDraw drawing model does not exist, so CoreGraphics is the default drawing model.
The CoreGraphics drawing model
If a plugin sets the drawing model to NPDrawingModelCoreGraphics, then the meanings of some of the NPAPI data structures change:
- NPWindow's 'window' field becomes a NP_CGContext:
/* NP_CGContext is the type of the NPWindow's 'window' when the * plugin specifies NPDrawingModelCoreGraphics as its drawing model. */ typedef struct NP_CGContext { CGContextRef context; WindowRef window; } NP_CGContext;
- NPRegion becomes a CGPathRef instead of a RgnHandle:
#if defined(XP_MAC) typedef RgnHandle NPRegion; #elif defined(XP_MACOSX) /* NPRegion's type depends on the drawing model specified by the plugin * (see NPNVpluginDrawingModel). * NPQDRegion represents a QuickDraw RgnHandle, and NPCGRegion represents * a CoreGraphics CGPathRef. */ typedef void *NPRegion; #ifndef NP_NO_QUICKDRAW typedef RgnHandle NPQDRegion; #endif typedef CGPathRef NPCGRegion; #endif /* XP_MAC */
Optimized drawing
From a performance standpoint, it is important for some plugins to restrict drawing to the window's "invalid region". This allows for more efficient repainting. Historically, Mac Netscape plugins have done this by getting the window or port's invalid region. CoreGraphics plugins should instead use the CGContextRef's clip path. Before sending an updateEvt to the plugin, the browser will intersect the CGContext's clip path with the plugin's invalid region. The plugin may then use functions like CGContextGetClipBoundingBox() to restrict drawing to only the clip region.
Bridging QuickDraw and CoreGraphics
You might be asking yourself, "Great... So now I can make a plugin that draws using CoreGraphics, but it will only run in browsers that support this NPAPI extension?!"
Don't worry! There is a way for plugins to draw using CoreGraphics, yet remain compatible with QuickDraw-only browsers. The idea is to use QDBeginCGContext() and QDEndCGContext() to obtain a CGContextRef for the CGrafPtr provided by the browser. We will be shipping some sample code to demonstrate this technique, but here is a little snippet for your enjoyment:
static CGContextRef beginQDPluginUpdate(NPWindow *window) { // window->window is an NPPort* since the browser is using QuickDraw NP_Port *npPort = ((NP_Port *)window->window); // Get the CGContext for the port CGContextRef cgContext; QDBeginCGContext(npPort->port, &cgContext); CGContextSaveGState(cgContext); // Set the CG clip path to the port's clip region -- QDBeginCGContext() // does not automatically respect the QuickDraw port's clip region. RgnHandle clipRegion = NewRgn(); GetPortClipRegion(npPort->port, clipRegion); Rect portBounds; GetPortBounds(npPort->port, &portBounds); ClipCGContextToRegion(cgContext, &portBounds, clipRegion); DisposeRgn(clipRegion); // Flip the CG context vertically -- its origin is at the lower left, // but QuickDraw's origin is at the upper left. CGContextTranslateCTM(cgContext, 0.0, portBounds.bottom - portBounds.top); CGContextScaleCTM(cgContext, 1.0, -1.0); return cgContext; }
static void endQDPluginUpdate(NPWindow *window, CGContextRef cgContext) { // Restore state (it was saved in beginQDPluginUpdate()) CGContextRestoreGState(cgContext); // If we had to prepare the CGContext for use in a QuickDraw-only browser, // restore its state and notify QD that the CG drawing sequence is over. CGContextFlush(cgContext); QDEndCGContext(((NP_Port *)window->window)->port, &cgContext); }
This trick will not work once QuickDraw is removed from Mac OS X. It is intended for plugin developers that want to draw using CoreGraphics, yet remain compatible with QuickDraw-only browsers that haven't adopted these proposed NPAPI extensions.
Your feedback is important!
If you are at all involved in Mac browser or plugin development, these changes will affect you. So make your voice heard! We're open to any questions or comments you might have about these proposed changes. Please post comments on the plugin-futures mailing list.