NPAPI:CoreGraphicsDrawing

From MozillaWiki
Jump to: navigation, search

Status

Accepted, ready for implementation.

Contributors

  • Last modified: April 22, 2010
  • Authors: Tim Omernick (Apple)
  • Contributors: Josh Aas (Mozilla Corporation)

Overview

The Core Graphics drawing model is an alternative drawing model for 32-bit Mac OS X plugins and the default drawing model for 64-bit Mac OS X plugins.

Note: This specification pre-dates the Cocoa specification, so it assumes the Carbon event model. Discussions of "changes" refer to differences from the QuickDraw drawing model. When using CoreGraphics with the Cocoa event model, changes in the Cocoa model may supersede information given here.

Negotiating Core Graphics Drawing

For documentation on negotiating drawing models, see NPAPI:Models. The drawing model variables for Core Graphics are:

  • NPDrawingModelCoreGraphics (NPDrawingModel = 1)
  • NPNVsupportsCoreGraphicsBool (NPNVariable = 2001)

Excluding QuickDraw

QuickDraw is default drawing model for 32-bit Mac OS X plugins. The QuickDraw drawing model does not exist for 64-bit Mac OS X. The drawing model variables for Quickdraw are:

  • NPDrawingModelQuickDraw (NPDrawingModel = 0)
  • NPNVsupportsQuickDrawBool (NPNVariable = 2000)

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

The Core Graphics 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 (under the Carbon event model) 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;

Note: the CG context here is always flipped for historical reasons.

- 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

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.

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.