Personal tools

NPAPI:Pepper

From MozillaWiki

Revision as of 08:19, 5 January 2011 by Vanuan (Talk | contribs)

Jump to: navigation, search

Contents

Status

Obsolete.

This was the first Pepper API design and was created to minimize the changes from legacy NPAPI, hoping to ease adoption by browser vendors and plugin developers. The Pepper APIs have been redesigned subsequent to the initial design, deviating more substantially from legacy NPAPI while, hopefully, also improving the interfaces. The revised interfaces are referred to as “PPAPI” or “Pepper2” (Reference).

PPAPI has been moved from Google Code to the Chromium subversion repo http://src.chromium.org/viewvc/chrome/trunk/src/ppapi/ to help with browser versioning and dependencies.

For PPAPI user documentation see http://code.google.com/p/ppapi/wiki/GettingStarted

For PPAPI developer documentation see https://sites.google.com/a/chromium.org/dev/developers/design-documents/pepper-plugin-implementation

Background

Over the past few months a number of us have also been discussing some of the issues facing NPAPI as a platform independent browser plugin framework. First, we feel there are some changes needed to NPAPI to keep up with recent developments in browser technology, such as out of process plugin execution. Second, while NPAPI provides an extensive framework for writing plugins, many end up relying on operating system or browser platform specific features. This is especially true of windowed plugins that implement 2D or 3D graphics, where almost the entirety of the plugin may consist of operating system specific graphics or event APIs. Third, both windowed and windowless plugins are difficult to composite with other layers correctly today, making it difficult for a page author to achieve the same look and feel across browsers and operating systems. This proposal intends to be a starting point for addressing these issues, and consists of four topics.

  1. Giving a clear semantics to NPAPI across browsers that implement plugins in a separate process from the renderer/browser itself.
  2. Integrating plugin rendering with the browser's compositing process, allowing HTML overlays, etc., to work correctly with plugins.
  3. Defining events, 2D rasterization, and an initial take on 3D graphics access in a way that is common across operating systems and browsers.
  4. Determining which plugins are available to a browser without loading the plugin. Although a much smaller issue, it is currently one of the more platform specific portions of NPAPI and one that lends itself to a relatively simple solution.

A somewhat related issue is how to extend NPAPI to provide platform independent access to new hardware or software features such as digital cameras, SD cards, bar code readers, accelerometers, webcams, microphones, etc. While certainly important, this is deferred to future discussions.

The "Pepper" Platform

To provide these improvements to NPAPI we propose that the changes below be another platform, called "Pepper", that may be implemented by a browser and requested by a plugin at startup. As the Pepper platform provides a number of APIs either not previously specified or previously tied to OS-dependent header files, we propose adding a new header, npapi_extensions.h.

Getting the Browser Extension Methods

A vector of function pointers is used to provide access to Pepper-specific browser functionality. This vector, called NPNExtensions, currently looks like

typedef struct _NPNExtensions
{
  /* Acquire Pepper device function pointers */
  NPAcquireDevicePtr aquireDevice;
  /* Clipboard functionality */
  NPCopyTextToClipboardPtr copyTextToClipboard;
  /* ... */
} NPNExtensions;

It is obtained by calling NPN_GetValue with

NPNVPepperExtensions

Getting a Plugin's Extension Methods

Plugins can also provide Pepper extensions for use by the browser.

typedef struct _NPPExtensions {
  NPPGetPrintExtensionsPtr getPrintExtensions;
  /* ... */
} NPPExtensions;

The browser obtains a plugin's Pepper interface by calling NPP_GetValue with

NPPVPepperExtensions

Out of process plugins

The current NPAPI model defines the threading model within one process such that whatever thread invokes NPP_New is the only thread that may invoke NPN_* functions. Several browsers either currently support or are considering moving NPAPI plugins to a separate process from the renderer process (responsible for rendering a page 's content). With these processes distinct, we have the following:

R = renderer process
Tr = thread in R that causes NPP_New to be invoked
P = plugin process
Tp = thread in P that invokes NPP_New in response to the renderer

Thread model for NPN_* calls

We propose that NPN_* calls, with only one exception, can only be made from Tp. This allows us to maintain an important invariant, namely that if Tp is executing any NPP code, then Tr is blocked. This eliminates the possibility of simultaneous JavaScript and plugin activities.

NPN_PluginThreadAsyncCall

The one exception to NPN_* calls is NPN_PluginThreadAsyncCall.

void    NP_LOADDS NPN_PluginThreadAsyncCall(NPP instance,
                                            void (*func) (void *),
                                            void *userData);

The semantics of NPN_PluginThreadAsyncCall remain fundamentally the same, just with respect to P:

  • It can be called from any thread in P.
  • Invoking it eventually causes an NPP callback on Tp to func, passing userData.

We make a couple of other implementation comments that make this more usable and help avoid possible deadlocks:

  • If two callbacks are requested by the same thread, they should be invoked in the same order they were requested.
  • The implementation of NPN_PluginThreadAsyncCall may not call func directly, even if called on Tp, because we need to guarantee the state of Tr and this risks deadlock.

We observe that implementing NPN_PluginThreadAsyncCall this way results in additional call/callback/call latency for NPN_* calls. We believe this is reasonable to provide a well-defined interaction, but realize we may need to address the efficiency of this mechanism.

Plugin Startup and Service Discovery

The current process of starting a plugin involves some differences on various platforms. In Pepper, the plugin must export

NPError API_CALL NP_Initialize(NPNetscapeFuncs* pNFuncs,
                               NPPluginFuncs* pPFuncs);

and

NPError NP_Shutdown(void);

There is no requirement for NP_GetEntryPoints.

Browsers currently determine which plugins provide support for which mime types by various mechanisms. A common trait of these mechanisms is the idea that the browser must load each plugin in succession to invoke an API to determine the types it provides. A single method not involving loading all the plugins is desired, but remains to be done.

Plugins and Rendering

We will use device context to refer to platform independent devices (e.g., audio, 3D graphics, hardware accelerators). To facilitate this, we propose the addition of a new struct type.

A plugin will request device contexts using the following structure.

typedef struct _NPDevice
{
  NPDeviceQueryCapabilityPtr queryCapability;
  NPDeviceQueryConfigPtr queryConfig;
  NPDeviceInitializeContextPtr initializeContext;
  NPDeviceSetStateContextPtr setStateContext;
  NPDeviceGetStateContextPtr getStateContext;
  NPDeviceFlushContextPtr flushContext;
  NPDeviceDestroyContextPtr destroyContext;
  NPDeviceCreateBufferPtr createBuffer;
  NPDeviceDestroyBufferPtr destroyBuffer;
  NPDeviceMapBufferPtr mapBuffer;
  NPDeviceThemeGetSize themeGetSize;
  NPDeviceThemePaint themePaint;
} NPDevice;

Query a Device for Capabilities and Configurations

typedef void NPDeviceConfig;

typedef NPError (*NPDeviceQueryCapabilityPtr(NPP instance,
                                             int32 capability,
                                             int32 *value);
typedef NPError (*NPDeviceQueryConfigPtr(NPP instance,
                                         const NPDeviceConfig* request,
                                         NPDeviceConfig* obtain);

Use queryCapability to ask a device about a specific capability. Use queryConfig to ask a device about a set of capabilities. The obtained configuration is the closest match to the requested configuration. If the obtained configuration is undesirable, the application is free to attempt additional queryConfig calls until a satisfactory configuration is discovered. Use the obtained configuration as input when initializing a device.

Getting a Device Context

typedef void NPDeviceContext;

typedef NPError (*NPDeviceInitializeContextPtr)(NPP instance,
                                                const NPDeviceConfig *config,
                                                NPDeviceContext* context);

Causes the creation of a device context for use by the specified instance.

Set / Get Device State

typedef NPError (*NPDeviceGetStateContextPtr)(NPP instance,
                                              NPDeviceContext* context,
                                              int32 state,
                                              intptr_t *value);

typedef NPError (*NPDeviceSetStateContextPtr)(NPP instance,
                                              NPDeviceContext* context,
                                              int32 state,
                                              intptr_t value);

Get/Set sideband state information with respect to device context.

Publishing a Context

typedef void (*NPDeviceFlushContextCallbackPtr)(NPP instance,
                                                NPDeviceContext* context,
                                                NPError err,
                                                void* userData);

typedef NPError (*NPDeviceFlushContextPtr)(NPP instance,
                                           NPDeviceContext* context,
                                           NPFlushContextCallbackPtr callback,
                                           void* userData);

Causes the contents of the context to be presented to the device for input/output to the user. Because the final input/output may be done by another process, the call is asynchronous. Return from the flush guarantees it is safe to write to the region again, but does not say that the data has reached the user. The callback is provided to add this capability. The callback should be invoked once the data has been output or an error has been detected.

If no callback is specified, the flush becomes a blocking call.

To facilitate low latency devices, flushContext() can be invoked from non-NPAPI threads (threads other than Tp).

Destroying a Device Context

typedef NPError (*NPDeviceDestroyContextPtr)(NPP instance,
                                             NPDeviceContext* context);

Causes the context specified to be destroyed. The memory pointed to by context may be freed and accesses are undefined.

Creating and Manipulating Buffers

Buffers are shared memory objects associated with a specific device context that are used to communicate data between processes in a multiprocess implementation. There are three fundamental operations

Creating a buffer

/* Create a buffer associated with a particular context. The usage of the */
/* buffer is device specific. The lifetime of the buffer is scoped with the */
/* lifetime of the context. */
typedef NPError (*NPDeviceCreateBufferPtr)(
    NPP instance,
    NPDeviceContext* context,
    size_t size,
    int32* id);

Mapping a buffer

/* Inserts the buffer into the address space of the caller.
   Unmapping implicitly happens when the buffer or context is destroyed. */
typedef struct _NPDeviceBuffer {
  void* ptr;
  size_t size;
} NPDeviceBuffer;

typedef NPError (*NPDeviceMapBufferPtr)(
    NPP instance,
    NPDeviceContext* context,
    int32 id,
    NPDeviceBuffer* buffer);

Destroying a buffer

/* Destroy a buffer associated with a particular context. */
typedef NPError (*NPDeviceDestroyBufferPtr)(
    NPP instance,
    NPDeviceContext* context,
    int32 id);

Optimizations and Legacy APIs

There is a possible performance opportunity that should be noted. Given the threading model we have defined, it is desirable to allow InitializeRenderContext and FlushRenderContext to be called from other plugin threads than Tp. This eliminates the need to do the associated NPN_PluginThreadAsyncCall, and avoids the context switch penalties that might be associated.

2D Rendering

Background

Old-style NPAPI plugins display 2D graphics in one of two modes: windowless or windowed, each with their own features and limitations. The plugin can specify which mode it would prefer to execute in.

Windowless plugins are inserted into the middle of the painting of the web page. As the page is being painted, the plugin is given the opportunity to draw the contents of the plugin directly over the previously-rendered contents of the page. This is very flexible, but has a number of downsides:

  • It assumes that the browser is using the platform-native surface to render the page (for example, an HDC on Windows). Some browsers may with to use third-party graphics libraries for additional flexibility.
  • It has no provision for an alpha channel. A plugin does antialiasing by blending itself directly onto the lower layers of the page. This poses problems for out-of-process plugins (see below) and prevents a number of optimizations.
  • It assumes that the plugin is executing in the same process as the page is being painted. Increasingly, browsers are moving plugins into separate processes, which requires significantly more effort on the part of the browser to emulate the in-process painting
  • It is platform-specific. Plugins must be specifically coded to support the native painting APIs of all host systems they run on.

Windowed plugins plugins are essentially given a handle to an operating system native window, from which all interaction by the plugin is completely platform-specific.

  • Windowed plugins rely even more on the system native painting and events than windowless ones.
  • Having native windows on top of the page makes it very difficult or impossible for the browser to draw page content above the plugin, interfering with a number of common web practices such as pop-up menus.
  • From the browser's perspective, it is difficult to manage the child windows. For example, keeping them and the page in sync when the page scrolls is challenging. There are also responsiveness challenges, in that a hung plugin can hang the entire browser UI by not processing messages in its window, even if it runs in another process or thread.

API Overview

We propose that only windowless plugins be supported, that compositing should be done outside the plugin, and that no native OS events should be delivered to the plugin. New APIs and events will be added to fill in the resulting holes in functionality.

The 2D device provides a buffer with an alpha channel for the plugin to paint to a region of the screen. The drawing model is a retained mode where the browser will keep the current image of the plugin in a backing store. The plugin is able to update all or part of this backing store via the 2D device API as it wishes. The painting of the page is then decoupled from the generation of the image.

The 2D API is particularly well suited to static or rarely-changing content. For example, a plugin implementing decoding of a new image type would decode the image and flush it to the browser only once, and would never have to execute any paint handlers or re-render the image.

Animation can be implemented in the 2D device API using the callback from the flush function. After the browser paints the image to the screen, it will call the plugin's specified callback. At this point, the plugin can generate a new frame. This callback notification is the rate limiting signal so the plugin does not generate images faster than they can be painted to the screen.

The 2D Device

typedef struct _NPDeviceContext2D
{
  /* Internal value used by the browser to identify this device.
   */
  void* reserved;

  /* A pointer to the pixel data. This data is 8-bit values in BGRA order in
   * memory. Each row will start |stride| bytes after the previous one.
   *
   * THIS DATA USES PREMULTIPLIED ALPHA. This means that each color channel has
   * been multiplied with the corresponding alpha, which makes compositing
   * easier. If any color channels have a value greater than the alpha value,
   * you'll likely get crazy colors and weird artifacts.
   */
  void* region;

  /* Length of each row of pixels in bytes. This may be larger than width * 4
   * if there is padding at the end of each row to help with alignment.
   */
  int32 stride;

  /* The dirty region that the plugin has painted into the buffer. This
   * will be initialized to the size of the plugin image in
   * initializeContextPtr. The plugin can change the values to only
   * update portions of the image.
   */
  struct {
    int32 left;
    int32 top;
    int32 right;
    int32 bottom;
  } dirty;
} NPDeviceContext2D;

Example

/* Get the 2D device function pointers. */
NPDevice* device2d = extensions->acquireDevice(npp, NPPepper2DDevice);

/* Create a context. there are currently no options
   in the 2D device to configure */
NPDeviceContext2DConfig config;
NPDeviceContext2D context;
device2d->initializeContext(npp, &config, &context);

/* Draw into the bits in context->region however you want. */

/* This example uses no callback, so the plugin will block until
   bits have been painted to the screen. */
device2d->flushContext(npp, &context, NULL, NULL);

3D Rendering

Overview

The details of 3D rendering are still being worked out. The general idea is that there will be a serialized set of OpenGL commands sent from the plugin to the browser for display on the video card. It is currently not decided whether the format of this command stream is standardized, or whether there will be a standardized API that generates a browser-specific command stream.

The 3D Device

Our proposal for the 3D drawing API is a command buffer between the plugin and a 3D renderer. The exact format of the commands and protocol is too long to embed here.  Please click here for the Pepper command buffer API

As with the generic device API, there are configuration options for 3D. There is currently only one configuration option for the 3D device, which is the size of the command buffer. Its likely additional configuration options will be added later.

typedef struct _NPDeviceContext3DConfig {
  int32 commandBufferEntries;
} NPDeviceContext3DConfig;

The 3D device is specified as follows:

typedef struct _NPDeviceContext3D
{
  void* reserved;

  /* If true, then a flush will only complete once the get offset has advanced
  * on the GPU thread. If false, then the get offset might have changed but
  * the GPU thread will respond as quickly as possible without guaranteeing
  * having made any progress in executing pending commands. Set to true
  * to ensure that progress is made or when flushing in a loop waiting for the
  * GPU to reach a certain state, for example in advancing beyond a particular
  * token. Set to false when flushing to query the current state, for example
  * whether an error has occurred.
  */
  bool waitForProgress;

  /* Buffer in which commands are stored. */
  void* commandBuffer;
  int32 commandBufferSize;

  /* Offset in command buffer reader has reached. Synchronized on flush. */
  int32 getOffset;

  /* Offset in command buffer writer has reached. Synchronized on flush. */
  int32 putOffset;

  /* Last processed token. Synchronized on flush. */
  int32 token;

  /* Error status. Synchronized on flush. */
  NPDeviceContext3DError error;
} NPDeviceContext3D;

The 3D device API specifies a number of errors that could be returned.

typedef enum _NPDeviceContext3DError {
  /* No error has ocurred. */
  NPDeviceContext3DError_NoError,

  /* The size of a command was invalid. */
  NPDeviceContext3DError_InvalidSize,

  /* An offset was out of bounds. */
  NPDeviceContext3DError_OutOfBounds,

  /* A command was not recognized. */
  NPDeviceContext3DError_UnknownCommand,

  /* The arguments to a command were invalid. */
  NPDeviceContext3DError_InvalidArguments,

  /* The 3D context was lost, for example due to a power management event. The
   * context must be destroyed and a new one created.
   */
  NPDeviceContext3DError_LostContext,

  /* Any other error. */
  NPDeviceContext3DError_GenericError
} NPDeviceContext3DError;

The structure and contents of the command buffer interface are to be described.

NPP_SetWindow and Windowless Plugins

Whereas currently NPP_SetWindow passes both some geometry information and a handle to a native window (for windowed plugins), in our proposal, it only conveys geometry and format information. For example.

typedef struct _NPWindow {
  void*    window;   // UNUSED
  uint32_t x;        // Position of plugin top left corner relative to top left
  uint32_t y;        // of renderer page. Y increases going down.
  uint32_t width;    // maximum window size
  uint32_t height;
  NPRect   clipRect; // UNUSED
  void*    ws_info;  // Pixel format of the raster backing store. A NPRasterWindowInfo struct.
  NPWindowType type; // UNUSED
} NPWindow;

Event Handling

Plugins should receive all their events from NPP_HandleEvent. We believe that standardizing the event types and payloads based on, for example, DOM events, would be sufficient to provide browser and OS independent events. If not, the goal can be accomplished by possibly extending the set of event types or data on the event structures to convey more information.

Background

We will use specifically sized types (int32, int16, int8, etc.) to avoid sizeof(int) and sizeof(wchar) differences between compilers and machine architectures, and have very strict padding and alignment specifications.

This specification is version 1.0 of events in Pepper. If future events are added, or additional fields are added to existing events, we'll need a way for the client applications to query (or negotiate) what version of events are supported by the browser. If significant changes are made to the event model, we may need to add additional trusted code to maintain backwards compatibility with existing plugin applications. This applies not only to new fields or changes to the ranges of existing fields, but is also especially important for changes or differences in behaviours across multiple operating systems (for example, are mouse movements reported outside the embedded area while a button is held down and the initial mouse down event occurred within the embedded area) Subsequent versions of Pepper events may need to support gesture & touch based events, such as finger pinching and stretching to support zoom in / zoom out for maps & photo editors.

The plugin can use NPN_GetValue() & NPN_SetValue() to query and set future event models. Currently, only version 1.0 model is supported, and it should be safe to assume that version 1.0 model will always be available, and will be the default at startup.

Additional Items

There is no timer event, see NPN_ScheduleTimer() and NPN_UnscheduleTimer() for timer support. There is no quit event during application shutdown, see JavaScript's "onunload" There is no resize event; see NPN_SetWindow(), which will be correctly serialized with respect to event order.

Currently, we are proposing a platform neutral event for focus gained/lost, and a similar event for minimize/background tab. There is also a proposal for NPAPI to support three new NPN functions: NPN_UnfocusInstance(), NPN_LostFocus(), and NPN_GotFocus(). The NPAPI proposal uses NPN functions in leu of events for a few reasons, two of which are: 1) they didn't want to define what the focus event should be for each OS platform, 2) allow the application to explicitly give up focus. Since PEPPER events are platform neutral, the 1st reason doesn't really apply here. The 2nd reason might be good enough to consider using AKH instead of focus events. The downside is that as more events become NPN_* functions, the event model starts to become an inconsistent mix of traditional events and NPN_* functions. https://wiki.mozilla.org/Plugins:AdvancedKeyHandling

Pepper NPAPI Event Structures

It is important that all compilers, on all supported platforms, both trusted and untrusted, preserve structure order, field size, and alignment padding, as these structures might be used as a bit copyable wire format between different processes. These seperate processses could be compiled using different compilers and/or compilier options, while sharing these structures via shared memory. For the definitions below, the byte offset for each field is in square brackets. Unused portions of the event structure should be treated as undefined data.

enum NPMouseButtons {
  // Each value explicitly set, and must match between trusted & untrusted code.
  NPMouseButton_None    = -1,
  NPMouseButton_Left    = 0,
  NPMouseButton_Middle  = 1,
  NPMouseButton_Right   = 2,
  // End of Pepper event specification version 1.0
  // Additional future mouse button enums go here...
};

enum NPEventTypes {
  // Each value explicitly set, and must match between trusted & untrusted code.
  NPEventType_Undefined   = -1,

  // events                         relevant union to use in NPEvent
  NPEventType_MouseDown   = 0,   // NPMouseEvent struct
  NPEventType_MouseUp     = 1,   // NPMouseEvent struct
  NPEventType_MouseMove   = 2,   // NPMouseEvent struct
  NPEventType_MouseEnter  = 3,   // NPMouseEvent struct
  NPEventType_MouseLeave  = 4,   // NPMouseEvent struct
  NPEventType_MouseWheel  = 5,   // NPMouseWheelEvent struct
  NPEventType_RawKeyDown  = 6,   // NPKeyEvent struct
  NPEventType_KeyDown     = 7,   // NPKeyEvent struct
  NPEventType_KeyUp       = 8,   // NPKeyEvent struct
  NPEventType_Char        = 9,   // NPCharEvent struct
  NPEventType_Minimize    = 10,  // NPMinimizeEvent struct
  NPEventType_Focus       = 11,  // NPFocusEvent struct
  NPEventType_Device      = 12,  // NPDeviceEvent struct
  // End of Pepper specific event specification version 1.0
  // Additional future Pepper events go here...
};

enum NPEventModifiers {
  // Each value explicitly set, and must match between trusted & untrusted code.
  NPEventModifier_ShiftKey         = 1 << 0;    // Does not differentiate between left/right keys
  NPEventModifier_ControlKey       = 1 << 1;    // Does not differentiate between left/right keys
  NPEventModifier_AltKey           = 1 << 2;    // Does not differentiate between left/right keys
  NPEventModifier_MetaKey          = 1 << 3;    // Does not differentiate between left/right keys
  NPEventModifier_IsKeyPad         = 1 << 4;
  NPEventModifier_IsAutoRepeat     = 1 << 5;
  NPEventModifier_LeftButtonDown   = 1 << 6;
  NPEventModifier_MiddleButtonDown = 1 << 7;
  NPEventModifier_RightButtonDown  = 1 << 8;
  // End of Pepper event specification version 1.0
  // Additional future event modifiers go here...
};

struct NPKeyEvent {
  // Structure layout must match between trusted & untrusted code.
  uint32 modifier;               // [0] : NPModifier
  uint32 normalizedKeyCode;      // [4] : key codes from Chromium's keyboard_codes_posix.h
};

struct NPCharacterEvent {
  uint32 modifier;               // [0]  : NPModifier
  uint16 text[4];                // [4]  : 16bit wchar
  uint16 unmodifiedText[4];      // [12] : 16bit wchar
  // End of Pepper event specification version 1.0
  // Additional future key event fields go here...
};

struct NPMouseEvent {
  // Structure layout must match between trusted & untrusted code.
  uint32 modifier;               // [0] : NPModifier
  int32 button;                  // [4] : NPMouseButtons
  int32 x;                       // [8] : Relative to upper left corner of embedded area, in units of pixels
  int32 y;                       // [12]: Relative to upper left corner of embedded area (+y down)
  int32 clickCount;              // [16]: Number of button clicks
  // End of Pepper event specification version 1.0
  // Additional future mouse event fields go here...
};

struct NPMouseWheelEvent {
  // Structure layout must match between trusted & untrusted code.
  uint32 modifier;               // [0] : NPModifier
  float deltaX;                  // [4] : Positive deltaX indicate scroll left, in scroll wheel units. 
  float deltaY;                  // [8] : Positive deltaY indicate scroll up, in scroll wheel units.
                                 //         On Windows, one scroll wheel click is a delta of 100.0
  float wheelTicksX;             // [12]: Positive wheelTicksX indicate scroll left.
  float wheelTicksY;             // [16]: Positive wheelTicksY indicate scroll up.
                                 //         Wheel ticks can be fractional values on certain devices.
  uint32 scrollByPage;           // [20]: 0 - scroll by line, 1 - scroll by page
  // End of Pepper event specification version 1.0
  // Additional future mouse wheel event fields go here...
};

struct NPDeviceEvent {
  // Structure layout must match between trusted & untrusted code.
  // This is a generic event type that devices (discovered via NPN_SetWindow) may use
  // to deliver events to NPN_HandleEvent().
  // Note: this area is under construction

  uint32 device_uid;             // [0] : unique id of device (comes in on PEPPER NPN_SetWindow)
  uint32 subtype;                // [4] : device event subtype
  uint8 generic[0];              // [8] : payload is typecast based on device uid & subtype
};

struct NPMinimizeEvent {
  // Structure layout must match between trusted & untrusted code.
  // Minimizing may also include becoming a background/foreground tab.
  int32 value;                   // [0] : New value
                                 //         0 = transitioning out of minimized state
                                 //         1 = transitioning to a minimized state
  // End of Pepper event specification version 1.0
  // Additional future minimize event fields go here...
};

struct NPFocusEvent {
  // Structure layout must match between trusted & untrusted code.
  // The embedded Pepper area is gaining or losing keyboard focus.
  int32 value;                   // [0] : New value
                                 //         0 = losing focus
                                 //         1 = gaining focus
  // End of Pepper event specification version 1.0
  // Additional future focus event fields go here...
};

struct NPEvent {
  // Structure layout must match between trusted & untrusted code.
  int32 type;                    // [0] : NPEventTypes
  uint32 size;                   // [4] : Size in bytes of _this_ event structure.
  double timeStampSeconds;       // [8] : Time of creation; seconds since epoch.

  union {
    // [16]: Info specific to each event type
    NPKeyEvent key;
    NPCharacterEvent character;
    NPMouseEvent mouse;
    NPMouseWheelEvent wheel;
    NPMinimizeEvent minimize;
    NPFocusEvent focus;
    NPDeviceEvent device;
    // End of Pepper event specification version 1.0
    // Additional future event type structures go here...
  };
};

// Keycodes used by NPKeyEvent.normalizedKeyCode (keyboard_codes_posix.h)

enum {
  VKEY_BACK = 0x08,
  VKEY_TAB = 0x09,
  VKEY_CLEAR = 0x0C,
  VKEY_RETURN = 0x0D,
  VKEY_SHIFT = 0x10,
  VKEY_CONTROL = 0x11,
  VKEY_MENU = 0x12,
  VKEY_PAUSE = 0x13,
  VKEY_CAPITAL = 0x14,
  VKEY_KANA = 0x15,
  VKEY_HANGUL = 0x15,
  VKEY_JUNJA = 0x17,
  VKEY_FINAL = 0x18,
  VKEY_HANJA = 0x19,
  VKEY_KANJI = 0x19,
  VKEY_ESCAPE = 0x1B,
  VKEY_CONVERT = 0x1C,
  VKEY_NONCONVERT = 0x1D,
  VKEY_ACCEPT = 0x1E,
  VKEY_MODECHANGE = 0x1F,
  VKEY_SPACE = 0x20,
  VKEY_PRIOR = 0x21,
  VKEY_NEXT = 0x22,
  VKEY_END = 0x23,
  VKEY_HOME = 0x24,
  VKEY_LEFT = 0x25,
  VKEY_UP = 0x26,
  VKEY_RIGHT = 0x27,
  VKEY_DOWN = 0x28,
  VKEY_SELECT = 0x29,
  VKEY_PRINT = 0x2A,
  VKEY_EXECUTE = 0x2B,
  VKEY_SNAPSHOT = 0x2C,
  VKEY_INSERT = 0x2D,
  VKEY_DELETE = 0x2E,
  VKEY_HELP = 0x2F,
  VKEY_0 = 0x30,
  VKEY_1 = 0x31,
  VKEY_2 = 0x32,
  VKEY_3 = 0x33,
  VKEY_4 = 0x34,
  VKEY_5 = 0x35,
  VKEY_6 = 0x36,
  VKEY_7 = 0x37,
  VKEY_8 = 0x38,
  VKEY_9 = 0x39,
  VKEY_A = 0x41,
  VKEY_B = 0x42,
  VKEY_C = 0x43,
  VKEY_D = 0x44,
  VKEY_E = 0x45,
  VKEY_F = 0x46,
  VKEY_G = 0x47,
  VKEY_H = 0x48,
  VKEY_I = 0x49,
  VKEY_J = 0x4A,
  VKEY_K = 0x4B,
  VKEY_L = 0x4C,
  VKEY_M = 0x4D,
  VKEY_N = 0x4E,
  VKEY_O = 0x4F,
  VKEY_P = 0x50,
  VKEY_Q = 0x51,
  VKEY_R = 0x52,
  VKEY_S = 0x53,
  VKEY_T = 0x54,
  VKEY_U = 0x55,
  VKEY_V = 0x56,
  VKEY_W = 0x57,
  VKEY_X = 0x58,
  VKEY_Y = 0x59,
  VKEY_Z = 0x5A,
  VKEY_LWIN = 0x5B,
  VKEY_RWIN = 0x5C,
  VKEY_APPS = 0x5D,
  VKEY_SLEEP = 0x5F,
  VKEY_NUMPAD0 = 0x60,
  VKEY_NUMPAD1 = 0x61,
  VKEY_NUMPAD2 = 0x62,
  VKEY_NUMPAD3 = 0x63,
  VKEY_NUMPAD4 = 0x64,
  VKEY_NUMPAD5 = 0x65,
  VKEY_NUMPAD6 = 0x66,
  VKEY_NUMPAD7 = 0x67,
  VKEY_NUMPAD8 = 0x68,
  VKEY_NUMPAD9 = 0x69,
  VKEY_MULTIPLY = 0x6A,
  VKEY_ADD = 0x6B,
  VKEY_SEPARATOR = 0x6C,
  VKEY_SUBTRACT = 0x6D,
  VKEY_DECIMAL = 0x6E,
  VKEY_DIVIDE = 0x6F,
  VKEY_F1 = 0x70,
  VKEY_F2 = 0x71,
  VKEY_F3 = 0x72,
  VKEY_F4 = 0x73,
  VKEY_F5 = 0x74,
  VKEY_F6 = 0x75,
  VKEY_F7 = 0x76,
  VKEY_F8 = 0x77,
  VKEY_F9 = 0x78,
  VKEY_F10 = 0x79,
  VKEY_F11 = 0x7A,
  VKEY_F12 = 0x7B,
  VKEY_F13 = 0x7C,
  VKEY_F14 = 0x7D,
  VKEY_F15 = 0x7E,
  VKEY_F16 = 0x7F,
  VKEY_F17 = 0x80,
  VKEY_F18 = 0x81,
  VKEY_F19 = 0x82,
  VKEY_F20 = 0x83,
  VKEY_F21 = 0x84,
  VKEY_F22 = 0x85,
  VKEY_F23 = 0x86,
  VKEY_F24 = 0x87,
  VKEY_NUMLOCK = 0x90,
  VKEY_SCROLL = 0x91,
  VKEY_LSHIFT = 0xA0,
  VKEY_RSHIFT = 0xA1,
  VKEY_LCONTROL = 0xA2,
  VKEY_RCONTROL = 0xA3,
  VKEY_LMENU = 0xA4,
  VKEY_RMENU = 0xA5,
  VKEY_BROWSER_BACK = 0xA6,
  VKEY_BROWSER_FORWARD = 0xA7,
  VKEY_BROWSER_REFRESH = 0xA8,
  VKEY_BROWSER_STOP = 0xA9,
  VKEY_BROWSER_SEARCH = 0xAA,
  VKEY_BROWSER_FAVORITES = 0xAB,
  VKEY_BROWSER_HOME = 0xAC,
  VKEY_VOLUME_MUTE = 0xAD,
  VKEY_VOLUME_DOWN = 0xAE,
  VKEY_VOLUME_UP = 0xAF,
  VKEY_MEDIA_NEXT_TRACK = 0xB0,
  VKEY_MEDIA_PREV_TRACK = 0xB1,
  VKEY_MEDIA_STOP = 0xB2,
  VKEY_MEDIA_PLAY_PAUSE = 0xB3,
  VKEY_MEDIA_LAUNCH_MAIL = 0xB4,
  VKEY_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5,
  VKEY_MEDIA_LAUNCH_APP1 = 0xB6,
  VKEY_MEDIA_LAUNCH_APP2 = 0xB7,
  VKEY_OEM_1 = 0xBA,
  VKEY_OEM_PLUS = 0xBB,
  VKEY_OEM_COMMA = 0xBC,
  VKEY_OEM_MINUS = 0xBD,
  VKEY_OEM_PERIOD = 0xBE,
  VKEY_OEM_2 = 0xBF,
  VKEY_OEM_3 = 0xC0,
  VKEY_OEM_4 = 0xDB,
  VKEY_OEM_5 = 0xDC,
  VKEY_OEM_6 = 0xDD,
  VKEY_OEM_7 = 0xDE,
  VKEY_OEM_8 = 0xDF,
  VKEY_OEM_102 = 0xE2,
  VKEY_PROCESSKEY = 0xE5,
  VKEY_PACKET = 0xE7,
  VKEY_ATTN = 0xF6,
  VKEY_CRSEL = 0xF7,
  VKEY_EXSEL = 0xF8,
  VKEY_EREOF = 0xF9,
  VKEY_PLAY = 0xFA,
  VKEY_ZOOM = 0xFB,
  VKEY_NONAME = 0xFC,
  VKEY_PA1 = 0xFD,
  VKEY_OEM_CLEAR = 0xFE,
  VKEY_UNKNOWN = 0
};

Pepper Audio

Brief: Pepper will feature very low level audio support, with an emphasis on low latency. To start, initial implementations can support 44.1kHz and 48kHz stereo int16 audio streams. The API can scale to include higher sample rates (96kHz), multi-channel output (5ch, 5.1ch, +more), floating point samples and audio input. It assumes higher level audio functionality, such as software mixing, will be layered on top with additional libraries.

The whole Pepper audio design document is too long to embed here.  Please click here for the Pepper Audio API

Clipboard

In addition to devices API below, the NPExtensions struct provides a function pointer that can be used to copy strings to the clipboard.

/* Copy UTF-8 string into clipboard */
typedef void (*NPCopyTextToClipboardPtr)(
    NPP instance,
    const char* content);

Themes

The theming API allows a plugin to draw native controls in its 2D context. For example, if its content can't fit inside its region, it can paint scrollbars and allow the user to scroll up and down. The plugin needs to be able to get the size of each element of a control and to paint them under different states (i.e. pressed/selected). For now, only scrollbars are in the API.

typedef struct _NPPoint {
  uint16 x;
  uint16 y;
} NPPoint;

typedef enum {
  NPThemeItemScrollbarDownArrow       = 0,
  NPThemeItemScrollbarLeftArrow       = 1,
  NPThemeItemScrollbarRightArrow      = 2,
  NPThemeItemScrollbarUpArrow         = 3,
  NPThemeItemScrollbarHorizontalThumb = 4,
  NPThemeItemScrollbarVerticalThumb   = 5,
  NPThemeItemScrollbarHoriztonalTrack = 6,
  NPThemeItemScrollbarVerticalTrack   = 7
} NPThemeItem;

typedef enum {
  NPThemeStateDisabled = 0,
  // Mouse is over this item.
  NPThemeStateHot      = 1,
  // Mouse is over another part of this component.  This is only used on Windows
  // Vista and above.  The plugin should pass it in, and the host will convert
  // it to NPThemeStateNormal if on other platforms or on Windows XP.
  NPThemeStateHover    = 2,
  NPThemeStateNormal   = 3,
  NPThemeStatePressed  = 4
} NPThemeState;

typedef struct _NPThemeParams {
  NPThemeItem item;
  NPThemeState state;
  NPRect location;
  // Used for scroll bar tracks, needed for classic theme in Windows which draws
  // a checkered pattern.
  NPPoint align;
} NPThemeParams;

/* Gets the size of the given theme component.  For variable sized items like */
/* vertical scrollbar tracks, the width will be the required width of the */
/* track while the height will be the minimum height. */
typedef NPError (*NPDeviceThemeGetSize)(
    NPP instance,
    NPThemeItem item,
    int* width,
    int* height);
/* Draw a themed item (i.e. scrollbar arrow). */
typedef NPError (*NPDeviceThemePaint)(
    NPP instance,
    NPDeviceContext* context,
    NPThemeParams* params);

Printing

Pepper modules can choose to export the Pepper printing interface. Today the interface is raster-oriented, but we plan to provide a vector interface in the future. To get the plugin print interface the browser can call the getPrintExtensions method on the extensions vector. This returns another vector of methods.

/* Returns NULL if the plugin does not support print extensions */
typedef NPPPrintExtensions* (*NPPGetPrintExtensionsPtr)(NPP instance);

/* TBD: Provide a vector interface for printing. We need to decide
 * on a vector format that can support embedded fonts. A vector format will
 * greatly reduce the size of the required output buffer
*/

typedef struct _NPPPrintExtensions {
  NPPPrintBeginPtr printBegin;
  NPPGetRasterDimensionsPtr getRasterDimensions;
  NPPPrintPageRasterPtr printPageRaster;
  NPPPrintEndPtr printEnd;
} NPPPrintExtensions;

To begin a print operation the browser calls the first method. This returns the total number of pages to print at the given printableArea size and DPI. printableArea is in points (a point is 1/72 of an inch). The plugin is expected to remember the values of printableArea and printerDPI for use in subsequent print interface calls. These values should be cleared by the printEnd method.

typedef NPError (*NPPPrintBeginPtr) (
    NPP instance,
    NPRect* printableArea,
    int32 printerDPI,
    int32* numPages);

The second method returns the required raster dimensions for the given page.

typedef NPError (*NPPGetRasterDimensionsPtr) (
    NPP instance,
    int32 pageNumber,
    int32* widthInPixels,
    int32* heightInPixels);

The third method rasterizes the specified page into a printSurface of the same format as used for the 2D device API.

typedef NPError (*NPPPrintPageRasterPtr) (
    NPP instance,
    int32 pageNumber,
    NPDeviceContext2D* printSurface);

The last method ends the print operation.

typedef NPError (*NPPPrintEndPtr) (NPP instance);