NPAPI:DOMCursors

From MozillaWiki
Jump to: navigation, search

Status

Accepted, ready for implementation.

Contributors

  • Last modified: April 8, 2011
  • Authors: Josh Aas (Mozilla Corporation)

Overview

This specification will allow plugins to control the cursor's appearance via the DOM rather than native cursor APIs. Currently browsers do not support controlling the cursor via the DOM because it conflicts with native cursor code, causing flickering.

Specification

A new variable, NPPVpluginUsesDOMForCursorBool (value = 22), will be added to control whether or not the plugin wishes to control the cursor via the DOM. If the browser does not support DOM cursors for plugins then an error (NPERR_GENERIC_ERROR recommended) should be returned from NPN_SetValue.

If the plugin is able to successfully set NPPVpluginUsesDOMForCursorBool to true then the following code can be used to set the cursor via the DOM:

/* Sets a custom cursor for the plugin element. The browser's NPAPI function
   structure is assumed to be at location "gBrowserFuncs".
   * instance: The plugin instance for which to set the cursor.
   * cursorData: Expected to be a data URI.
   * fallbackCursor: Expected to be a string matching a CSS cursor.

   Example which sets the cursor to a red dot:
     setCustomCursor(instance,
       "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAB"
       "GdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA"
       "AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0"
       "NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXM"
       "McXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg==",
       "pointer");
 */
void setCustomCursor(NPP instance, const char* cursorData, const char* fallbackCursor) {
  if (!gBrowserFuncs ||
      !gBrowserFuncs->getvalue ||
      !gBrowserFuncs->releasevariantvalue ||
      !gBrowserFuncs->hasproperty ||
      !gBrowserFuncs->getproperty ||
      !gBrowserFuncs->setproperty ||
      !gBrowserFuncs->getstringidentifier ||
      !gBrowserFuncs->memalloc) {
    return;
  }

  char* cValue = (char*)gBrowserFuncs->memalloc(9 + strlen(cursorData) +
                                                strlen(fallbackCursor) + 1);
  if (!cValue) {
    return;
  }
  cValue[0] = 0;
  strcat(cValue, "url(\"");
  strcat(cValue, cursorData);
  strcat(cValue, "\"), ");
  strcat(cValue, fallbackCursor);
  
  NPVariant vString;
  STRINGZ_TO_NPVARIANT(cValue, vString);
  
  NPObject* pluginObject = NULL;
  NPError err = gBrowserFuncs->getvalue(instance, NPNVPluginElementNPObject,
                                        &pluginObject);
  if (err == NPERR_NO_ERROR && pluginObject) {
    NPIdentifier styleID = gBrowserFuncs->getstringidentifier("style");
    if (gBrowserFuncs->hasproperty(instance, pluginObject, styleID)) {
      NPVariant styleVariant;
      if (gBrowserFuncs->getproperty(instance, pluginObject, styleID, &styleVariant)) {
        if (NPVARIANT_IS_OBJECT(styleVariant)) {
          NPObject* styleObject = NPVARIANT_TO_OBJECT(styleVariant);
          NPIdentifier cursorID = gBrowserFuncs->getstringidentifier("cursor");
          if (gBrowserFuncs->hasproperty(instance, styleObject, cursorID)) {
            gBrowserFuncs->setproperty(instance, styleObject, cursorID, &vString);
          }
        }
        gBrowserFuncs->releasevariantvalue(&styleVariant);
      }
    }
    gBrowserFuncs->releaseobject(pluginObject);
  }
  gBrowserFuncs->releasevariantvalue(&vString);
}