Files
NotAlexNoyleandClaude Fable 5.1 62df604c54 Licensing audit: notices for everything bundled, no borrowed marks
The owner: "ensure that all software patent and trademark licenses in
the repo are being respected". A read-only audit of what the packages
carry found no blocker and these gaps, all closed here (the record is
impl-review-findings-6.md, "Licensing audit"):

- NOTICE names the runtime the engine ships with: glibc 2.23 as
  crosstool-NG modifies it (LGPL-2.1), the GCC 9.4.0 runtime (GPL-3.0
  with the Runtime Library Exception), and the eight Debian jessie
  libraries, with the FreeType disclaimer, Lato, the hyphenation
  patterns, and where the corresponding source is. licenses/ gains
  LGPL-2.1, GPL-3.0 and the GCC exception from the pinned tarballs and
  Debian's copyright files from the sysroot; every package ships all of
  licenses/ and CREDITS.md, checked in the payload preflight.
- NOTICE names the modified engine's source (the fork, branch, pinned
  commit, base release, the patches), as MPL-2.0 3.2 asks.
- README and LICENSE no longer call the packages Apache-2.0 and MPL-2.0
  only; the dead licensing.shtml reference is replaced by the UXP
  LICENSE and TRADEMARK files and Moonchild's legal and redist pages.
- Apache-2.0 4(b) change notices on the 29 HP-derived files changed
  since import.
- A drawn magnifier is the DuckDuckGo engines' icon; Google's logo is
  Google's only; the unused Bing logo is gone.
- The engine's services-sync.js defaults pointed at Moonchild's Sync,
  key server and add-on host: blanked at bundle time, checked.
- The "Blazer" keyword, the Goanna-mark tagline, a stray screenshot and
  a .bak dropped; the HP SDK's terms stated where it is downloaded;
  CREDITS records the logo's origin and the screenshot strip's licence.

Deferred to the next engine build: about:credits' URL and
--disable-ffmpeg (the system-libavcodec path is dead on the device).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XM9EDSp83ZFRhggY4RCT9X
2026-10-14 13:57:20 -04:00

1319 lines
40 KiB
C++

/* @@@LICENSE
*
* Copyright (c) 2012 Hewlett-Packard Development Company, L.P.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
LICENSE@@@ */
/* Modified by the Jihad Browser project (2026), per Apache-2.0 section 4(b): this file differs from
* HP's isis-project original. The changes are this repository's git history for this file. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <glib.h>
#include "AdapterBase.h"
/*
Outstanding Issues:
===================
* pen events (at least move) are passed to browser even when we return true,
so dragging across an adapter's view area will cause it to become selected like text,
and colored blue.
* When cursor blinks in a text field outside an adapters area, we receive a paint event
for every cursor blink.
* Invalid rectangles are not prperly respected -- paint events are always for the entire view.
*/
static char g_szAdapterName[512] = "Palm Native Adapter";
static char g_szAdapterDescription[512] = "Palm Adapter to native service";
// -----------------------------------------------------------------------------------
// Holds global pointers to NPN APIs.
// We provide shims in AdapterBase that handle providing the correct instance pointer, etc.
static NPNetscapeFuncs sBrowserFuncs;
static NPIdentifier sEventListenerID = NULL; // Identifier for finding/invoking methods on the adapter's event listener.
// These values are initially provided in PrvNPP_New(), but since we don't actually
// instantiate the adapter instance until PrvNPP_SetValue() is called with the main loop,
// we need to temporarily save them here so they can still be passed to AdapterCreate().
// We are guaranteed to receive the PrvNPP_SetValue() call immediately after PrvNPP_New() returns.
static int16_t gArgc = 0;
static char** gArgn = NULL;
static char** gArgv = NULL;
// Structure that defines the methods for our "javascript object".
NPClass AdapterBase::sPluginClass = {
NP_CLASS_STRUCT_VERSION_CTOR,
AdapterBase::PrvObjAllocate,
AdapterBase::PrvObjDeallocate,
AdapterBase::PrvObjInvalidate,
AdapterBase::PrvObjHasMethod,
AdapterBase::PrvObjInvoke,
AdapterBase::PrvObjInvokeDefault,
AdapterBase::PrvObjHasProperty,
AdapterBase::PrvObjGetProperty,
AdapterBase::PrvObjSetProperty,
AdapterBase::PrvObjRemoveProperty,
AdapterBase::PrvObjEnumerate,
AdapterBase::PrvObjConstruct
};
struct AdapterNPObj {
NPObject obj;
AdapterBase *adapter;
};
// -----------------------------------------------------------------------------------
// AdapterBase "real" implementation
// -----------------------------------------------------------------------------------
// accessor
NPNetscapeFuncs *AdapterBase::getFuncs()
{
return &sBrowserFuncs;
}
AdapterBase::AdapterBase(NPP instance, bool cacheAdapter, bool useGraphicsContext) :
mMainLoop(NULL),
mInstance(instance),
mNPObject(NULL),
mDOMObject(NULL),
mJSIdentifiers(NULL),
mJSMethods(NULL),
mJSMethodCount(0),
mCacheAdapter(cacheAdapter),
mUseGraphicsContext(useGraphicsContext)
{
memset(&mWindow, 0, sizeof(mWindow));
memset(&mPalmWindow, 0, sizeof(mPalmWindow));
instance->pdata = this;
// Lookup the plugin's DOM object so we can make calls on it using InvokeMethod():
sBrowserFuncs.getvalue(instance, NPNVPluginElementNPObject, &mDOMObject);
}
AdapterBase::~AdapterBase(void)
{
TRACE("Congratulations, your adapter was not leaked!");
}
void AdapterBase::InstanceDestroyed(void)
{
}
/**
* Converts a NPString to a "C" style null terminated string.
*
* @returns the newly allocated string which the caller is responsible for freeing using ::free().
*/
char* AdapterBase::NPStringToString(const NPString& str)
{
char* s = (char*) malloc(str.UTF8Length + 1);
if (str.UTF8Length > 0)
memcpy(s, str.UTF8Characters, str.UTF8Length);
s[str.UTF8Length] = '\0';
return s;
}
/**
* A utility function to determine if a variant is or can be converted to an integer type.
*/
bool AdapterBase::IsIntegerVariant(const NPVariant *variant)
{
return variant != NULL && IsIntegerVariant(*variant);
}
bool AdapterBase::IsIntegerVariant(const NPVariant &variant)
{
return NPVARIANT_IS_DOUBLE(variant) || NPVARIANT_IS_INT32(variant) || NPVARIANT_IS_BOOLEAN(variant);
}
/**
* A utility function to convert a variant to an integer type. The caller should determine that
* this call can succed by first calling IsIntegerVariant.
*
* @returns The number (rounded down if type is double) or zero if the variant cannot be converted.
*/
int AdapterBase::VariantToInteger(const NPVariant *variant)
{
return VariantToInteger(*variant);
}
int AdapterBase::VariantToInteger(const NPVariant &variant)
{
if (NPVARIANT_IS_INT32(variant))
return NPVARIANT_TO_INT32(variant);
else if (NPVARIANT_IS_DOUBLE(variant))
return static_cast<int>(NPVARIANT_TO_DOUBLE(variant));
else if (NPVARIANT_IS_BOOLEAN(variant))
return NPVARIANT_TO_BOOLEAN(variant) ? 1 : 0;
else
return 0;
}
/**
* A utility function to determine if a variant is or can be converted to a double type.
*/
bool AdapterBase::IsDoubleVariant(const NPVariant *variant)
{
return variant != NULL && IsDoubleVariant(*variant);
}
bool AdapterBase::IsDoubleVariant(const NPVariant& variant)
{
return NPVARIANT_IS_DOUBLE(variant) || NPVARIANT_IS_INT32(variant) || NPVARIANT_IS_BOOLEAN(variant);
}
/**
* A utility function to convert a variant to an double type. The caller should determine that
* this call can succed by first calling IsDoubleVariant.
*
* @returns The number or zero if the variant cannot be converted.
*/
double AdapterBase::VariantToDouble(const NPVariant *variant)
{
return VariantToDouble(*variant);
}
double AdapterBase::VariantToDouble(const NPVariant &variant)
{
if (NPVARIANT_IS_DOUBLE(variant))
return NPVARIANT_TO_DOUBLE(variant);
else if (NPVARIANT_IS_INT32(variant))
return static_cast<double>(NPVARIANT_TO_INT32(variant));
else if (NPVARIANT_IS_BOOLEAN(variant))
return NPVARIANT_TO_BOOLEAN(variant) ? 1.0 : 0.0;
else
return 0.0;
}
/**
* A utility function to determine if a variant is or can be converted to a boolean type.
*/
bool AdapterBase::IsBooleanVariant(const NPVariant *variant)
{
return variant != NULL && IsBooleanVariant(*variant);
}
bool AdapterBase::IsBooleanVariant(const NPVariant& variant)
{
return NPVARIANT_IS_DOUBLE(variant) || NPVARIANT_IS_INT32(variant) || NPVARIANT_IS_BOOLEAN(variant);
}
/**
* A utility function to convert a variant to an boolean type. The caller should determine that
* this call can succed by first calling IsBooleanVariant.
*
* @returns The number or zero if the variant cannot be converted.
*/
bool AdapterBase::VariantToBoolean(const NPVariant *variant)
{
if (NPVARIANT_IS_BOOLEAN(*variant))
return NPVARIANT_TO_BOOLEAN(*variant);
else if (NPVARIANT_IS_INT32(*variant))
return NPVARIANT_TO_INT32(*variant) != 0;
else if (NPVARIANT_IS_DOUBLE(*variant))
return NPVARIANT_TO_DOUBLE(*variant) != 0.0;
else
return false;
}
bool AdapterBase::VariantToBoolean(const NPVariant& variant)
{
return VariantToBoolean(&variant);
}
void AdapterBase::PrvPaint(NpPalmDrawEvent* event)
{
if(mPalmWindow.bpp != 32) {
fprintf(stderr, "WARNING - %s: rendering only supported in 32 bpp\n", __FUNCTION__);
return;
}
/*
Normally, the source rectangle indicated by event->srcLeft/Top/Right/Bottom should be scaled according to
palmWin->scaleFactor, and copied to event->dstBuffer (which is already set to the correct X/Y location).
But in Luna, adapters will always run at 100% scaling, so we can hide this from subclass implementations.
*/
double scaling = mPalmWindow.scaleFactor;
// printf("Scaling: %f, %lf\n", mPalmWindow.scaleFactor, scaling);
NpPalmDrawEvent event2;
if(scaling != 1.0) {
fprintf(stderr, "WARNING - %s: Auto-scaling coordinates to recover from bad scale factor.\n", __FUNCTION__);
// Prevent tragedy in cases where we get funky scaling factor, even though it should always be 1.0.
event2 = *event;
event2.srcLeft = (int32_t)(event2.srcLeft *scaling);
event2.srcTop = (int32_t)(event2.srcTop *scaling);
event2.srcRight = (int32_t)(event2.srcRight *scaling);
event2.srcBottom = (int32_t)(event2.srcBottom *scaling);
event = &event2;
mPalmWindow.scaleFactor = 1.0;
}
//TRACE("srcRect: (%d,%d) w:%d, h:%d", event->srcLeft, event->srcTop, event->srcRight - event->srcLeft, event->srcBottom - event->srcTop);
// Call subclass implementation:
handlePaint(event);
return;
}
/*
Searches the list of registered method identifiers to see if we
support the requested method. Returns the method pointer if so, NULL otherwise.
*/
JSMethodPtr AdapterBase::PrvFindMethod(NPIdentifier name)
{
// We should be able to assume that the method IDs have been initialized already,
// since it happens when the scriptable object is allocated in PrvNPP_GetValue().
for(uint32_t i=0; i<mJSMethodCount; i++)
{
if(mJSIdentifiers[i] == name)
{
return mJSMethods[i];
}
}
// If method wasn't found, look it up & print an error to ease debugging.
// Not really needed. It turns out this legitimately fails a lot, and the
// browser prints an error when you try to call a non-existant method.
// NPUTF8 *nameStr = sBrowserFuncs.utf8fromidentifier(name);
// TRACE(" Could not find method '%s'.", nameStr ? nameStr : "(null)");
// sBrowserFuncs.memfree(nameStr);
return NULL;
}
/*
Helper function.
This initializes the NPPluginFuncs structure with pointers to all the static
entrypoints WebKit may use to call into the adapter. We provide static private
implementations which take care of calling non-static methods with the appropriate
AdapterBase instance.
*/
void AdapterBase::InitializePluginFuncs(NPPluginFuncs* pPluginFuncs)
{
pPluginFuncs->newp = AdapterBase::PrvNPP_New;
pPluginFuncs->destroy = AdapterBase::PrvNPP_Destroy;
pPluginFuncs->setwindow = AdapterBase::PrvNPP_SetWindow;
pPluginFuncs->newstream = AdapterBase::PrvNPP_NewStream;
pPluginFuncs->destroystream = AdapterBase::PrvNPP_DestroyStream;
pPluginFuncs->asfile = AdapterBase::PrvNPP_StreamAsFile;
pPluginFuncs->writeready = AdapterBase::PrvNPP_WriteReady;
pPluginFuncs->write = AdapterBase::PrvNPP_Write;
pPluginFuncs->print = AdapterBase::PrvNPP_Print;
pPluginFuncs->event = AdapterBase::PrvNPP_HandleEvent;
pPluginFuncs->urlnotify = AdapterBase::PrvNPP_UrlNotify;
pPluginFuncs->javaClass = 0;
pPluginFuncs->getvalue = AdapterBase::PrvNPP_GetValue;
pPluginFuncs->setvalue = AdapterBase::PrvNPP_SetValue;
}
bool AdapterBase::InvokeEventListener(NPIdentifier methodName,
const NPVariant *args, uint32_t argCount, NPVariant *result)
{
NPVariant eventListener;
bool success = false;
// Try to obtain the event listener.
// We look it up for each call in case it's been changed.
eventListener.type = NPVariantType_Void;
success = sBrowserFuncs.getproperty(mInstance, mDOMObject, sEventListenerID, &eventListener);
// We can proceed if there's an event listener...
if(success)
{
// Invoke indicated method on the event listener, as long as the listener's an object:
if(NPVARIANT_IS_OBJECT(eventListener))
{
success = PrvInvokeMethod(NPVARIANT_TO_OBJECT(eventListener), methodName, args, argCount, result);
}
else success = false;
// Release our reference on the event listener object:
NPN_ReleaseVariantValue(&eventListener);
}
return success;
}
bool AdapterBase::InvokeAdapter(NPIdentifier methodName,
const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return PrvInvokeMethod(mDOMObject, methodName, args, argCount, result);
}
/**
* Throw a JavaScript exception.
*
* @The exception message to set.
*/
void AdapterBase::ThrowException(const char* msg)
{
sBrowserFuncs.setexception(mDOMObject, msg);
}
bool AdapterBase::PrvInvokeMethod(NPObject *obj, NPIdentifier methodName,
const NPVariant *args, uint32_t argCount, NPVariant *result)
{
NPVariant localResult;
bool success = false;
localResult.type = NPVariantType_Void;
success = sBrowserFuncs.invoke(mInstance, obj, methodName, args, argCount, &localResult);
// Return method invocation result to the caller, if desired.
// Or release the value if the caller doesn't want it.
if(success)
{
if(result != NULL)
*result = localResult;
else
NPN_ReleaseVariantValue(&localResult);
}
return success;
}
// -----------------------------------------------------------------------------------
// Utility routines for saving argn & argv.
// We can't use g_strdupv() since the arrays are apparently not null terminated.
// -----------------------------------------------------------------------------------
char** PrvDupArgv(int argc, char**argv) {
if(argc == 0 || argv == NULL)
return NULL;
char **newargs = g_new0(char*, argc+1);
for(int i=0; i<argc; i++)
{
newargs[i] = g_strdup(argv[i]);
}
return newargs;
}
void PrvFreeArgv(char**argv)
{
g_strfreev(argv);
}
// -----------------------------------------------------------------------------------
// NPAPI Exported Entrypoints.
// These 4 C hooks are the only ones we need to export from the adapter library.
// They are described in AdapterBase.h.
// All the rest are handled via procedure pointers, configured in NP_Initialize().
// -----------------------------------------------------------------------------------
/**
* Return the MIME type of this plugin.
*
* @see http://gplflash.sourceforge.net/gplflash2_blog/npapi.html#SEC12
*/
extern "C" DLLEXPORT
char* NP_GetMIMEDescription()
{
return const_cast<char*>(AdapterGetMIMEDescription());
}
extern "C" DLLEXPORT
NPError NP_Initialize(NPNetscapeFuncs* pBrowserFuncs, NPPluginFuncs* pPluginFuncs)
{
memcpy(&sBrowserFuncs, pBrowserFuncs, sizeof(NPNetscapeFuncs));
AdapterBase::InitializePluginFuncs(pPluginFuncs);
// We only need to look up this identifier once, so it's static.
// It's used in InvokeMethod(), to send method calls to the adapter's
// designated event listener if available.
sEventListenerID = AdapterBase::NPN_GetStringIdentifier("eventListener");
return AdapterLibInitialize();
}
extern "C" DLLEXPORT
NPError NP_Shutdown(void)
{
return NPERR_GENERIC_ERROR;
}
/**
* @see https://developer.mozilla.org/en/NP_GetValue.
*/
extern "C" DLLEXPORT
NPError NP_GetValue(void *future, NPPVariable aVariable, void *aValue)
{
NPError err = NPERR_NO_ERROR;
switch (aVariable) {
case NPPVpluginNameString:
*static_cast<char**>(aValue) = g_szAdapterName;
break;
case NPPVpluginDescriptionString:
*static_cast<char**>(aValue) = g_szAdapterDescription;
break;
default:
err = NPERR_INVALID_PARAM;
}
return err;
}
// -----------------------------------------------------------------------------------
// Static implementations of the NPP_* APIs.
// These are the C entrypoints typically required to be implemented by a browser
// plugin. They're provided to the browser as procedure pointers, through NP_Initialize().
// -----------------------------------------------------------------------------------
/*
Called by WebKit to allocate a new instance of the adapter.
Since we'd like a GMainLoop at initialization time, we defer the actual instantiation until
we have the loop.
*/
NPError AdapterBase::PrvNPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc,
char* argn[], char* argv[], NPSavedData* saved)
{
// We don't actually create the Adapter instance here, since the GMainLoop hasn't been set yet,
// and this is usually very helpful to have at initialization time. So, we just set pData to NULL,
// and then wait until the GMainLoop is set to actually create the instance.
// This is guaranteed to happen immediately after NPP_New() returns.
instance->pdata = NULL;
gArgc = argc;
gArgn = PrvDupArgv(argc, argn);
gArgv = PrvDupArgv(argc, argv);
return NPERR_NO_ERROR;
}
/*
Called when the page is closed, or the plugin instance is for some other reason no longer needed.
Deletes the AdapterBase subclass instance, or just marks it as would-be-deleted if the JavaScript side still has references to it.
*/
NPError AdapterBase::PrvNPP_Destroy(NPP instance, NPSavedData** save)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return NPERR_GENERIC_ERROR;
}
AdapterBase* a = (AdapterBase*) instance->pdata;
if(a != NULL) {
// Call the virtual destroy method for adapters that want to do things like
// disconnect from their servers when the plugin is destroyed, even though the
// JavaScript system may still hold references to the object and keep it alive.
a->InstanceDestroyed();
// Release the reference the plugin instance was holding on the JS object, if any.
// Sometimes, this will cause AdapterBase::PrvObjDeallocate() to be called also.
if(a->mNPObject != NULL)
NPN_ReleaseObject(&a->mNPObject->obj);
a->mInstance = NULL;
if (a->mDOMObject != NULL)
NPN_ReleaseObject(a->mDOMObject);
a->mDOMObject = NULL;
// if there's no live javascript references to the adapter, then delete it.
// If it's not deleted here, then it should happen in PrvObjectDeallocate().
if(a->mNPObject == NULL) {
delete a;
}
}
instance->pdata = NULL;
return NPERR_NO_ERROR;
}
/*
Called before we receive a paint event, and any time our "window" (area on the page) changes.
TODO: Bug? Currently seems to be called TWICE before each paint event.
*/
NPError AdapterBase::PrvNPP_SetWindow(NPP instance, NPWindow* window)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return NPERR_GENERIC_ERROR;
}
AdapterBase* a = (AdapterBase*) instance->pdata;
if (!a) {
fprintf(stderr, "WARNING - %s no adapter base.\n", __FUNCTION__);
return NPERR_GENERIC_ERROR;
}
if (window==NULL || window->window == NULL) {
fprintf(stderr, "Window is null\n");
return NPERR_GENERIC_ERROR;
}
NpPalmWindow* palmWin = (NpPalmWindow*) window->window;
if (!palmWin)
return NPERR_NO_ERROR;
double scaling = palmWin->scaleFactor;
if(scaling != 1.0) {
fprintf(stderr, "WARNING: AdapterBase::PrvNPP_SetWindow(): Scaling factor is %f, 1.0 expected.\n"
"Do you have 'EnableFitWidth=false' in your /etc/palm/browser.conf?\n", (float)scaling);
}
// only update data if its changed from the old settings, since
// WebKit sometimes calls NPP_SetWindow when nothing has changed
if (a->mWindow.x != window->x ||
a->mWindow.y != window->y ||
a->mWindow.width != window->width ||
a->mWindow.height != window->height ||
a->mPalmWindow.visible != palmWin->visible ||
a->mPalmWindow.scaleFactor != palmWin->scaleFactor) {
a->mWindow = *window;
a->mPalmWindow = *palmWin;
a->mWindow.window = &a->mPalmWindow;
// TRACE("Set window to (%ld,%ld) w:%lu, h:%lu", window->x, window->y, window->width, window->height);
a->handleWindowChange(window);
}
return NPERR_NO_ERROR;
}
NPError AdapterBase::handleNewStream(NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
{
if (stype)
*stype = NP_NORMAL;
return NPERR_NO_ERROR;
}
int32_t AdapterBase::handleWriteReady(NPStream* stream)
{
// We don't accept streamed data, but if we return 0 here, then the browser will try to resend data at intervals,
// to see if we're ready yet. So, we return a small number, and then cause the stream to be destroyed when the
// write actually happens by returning a negative number there. This way, everything is cleaned up.
return 128;
}
/**
* Delivers data to a plug-in instance.
*/
int32_t AdapterBase::handleWrite(NPStream* stream, int32_t offset, int32_t len, void* buffer)
{
return -1; // destroy the stream.
}
/**
* Tells the plug-in that a stream is about to be closed or destroyed.
*/
NPError AdapterBase::handleDestroyStream(NPStream* stream, NPReason reason)
{
return NPERR_NO_ERROR;
}
/**
* Notifies a plug-in instance of a new data stream.
*/
NPError AdapterBase::PrvNPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return NPERR_GENERIC_ERROR;
}
return static_cast<AdapterBase*>(instance->pdata)->handleNewStream(type, stream, seekable, stype);
}
/**
* Tells the plug-in that a stream is about to be closed or destroyed.
*
* @see http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/npp_api3.html#999152
*/
NPError AdapterBase::PrvNPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return NPERR_GENERIC_ERROR;
}
return static_cast<AdapterBase*>(instance->pdata)->handleDestroyStream(stream, reason);
}
/* Unimplemented. */
void AdapterBase::PrvNPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname)
{
return;
}
/**
* Determines maximum number of bytes that the plug-in can consume.
*
* @see http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/npp_api17.html#999521
*/
int32_t AdapterBase::PrvNPP_WriteReady(NPP instance, NPStream* stream)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return 128; // we can receive a small amount of data at a time.
}
return static_cast<AdapterBase*>(instance->pdata)->handleWriteReady(stream);
}
/**
* Delivers data to a plug-in instance.
*
* @see http://devedge-temp.mozilla.org/library/manuals/2002/plugin/1.0/npp_api16.html#999497
*/
int32_t AdapterBase::PrvNPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return -1; // destroys the stream
}
return static_cast<AdapterBase*>(instance->pdata)->handleWrite(stream, offset, len, buffer);
}
/* Unimplemented. */
void AdapterBase::PrvNPP_Print(NPP instance, NPPrint* platformPrint)
{ }
/*
Called by webkit to pass all manner of events into the adapter.
We do minimal error checking, a bit of massaging in some cases,
and pass the events on to pure virtual handler methods.
*/
int16_t AdapterBase::PrvNPP_HandleEvent(NPP instance, void* event)
{
if(instance->pdata == NULL) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return false;
}
AdapterBase *a = (AdapterBase*)instance->pdata;
int16_t result = false;
NPEvent* npEvent = (NPEvent*) event;
if (!npEvent) {
return 0;
}
NpPalmPenEvent penEvent;
// TRACE("type=%d", (int)npEvent->eventType);
switch (npEvent->eventType) {
case (npPalmDrawEvent): {
a->PrvPaint(&(npEvent->data.drawEvent));
result = true;
break;
}
case (npPalmPenDownEvent): {
penEvent = npEvent->data.penEvent;
penEvent.xCoord -= a->mWindow.x;
penEvent.yCoord -= a->mWindow.y;
result = a->handlePenDown(&penEvent);
break;
}
case (npPalmPenMoveEvent): {
penEvent = npEvent->data.penEvent;
penEvent.xCoord -= a->mWindow.x;
penEvent.yCoord -= a->mWindow.y;
result = a->handlePenMove(&penEvent);
break;
}
case (npPalmPenUpEvent): {
penEvent = npEvent->data.penEvent;
penEvent.xCoord -= a->mWindow.x;
penEvent.yCoord -= a->mWindow.y;
result = a->handlePenUp(&penEvent);
break;
}
case (npPalmPenClickEvent): {
penEvent = npEvent->data.penEvent;
penEvent.xCoord -= a->mWindow.x;
penEvent.yCoord -= a->mWindow.y;
result = a->handlePenClick(&penEvent);
break;
}
case (npPalmPenDoubleClickEvent): {
penEvent = npEvent->data.penEvent;
penEvent.xCoord -= a->mWindow.x;
penEvent.yCoord -= a->mWindow.y;
result = a->handlePenDoubleClick(&penEvent);
break;
}
case (npPalmKeyDownEvent): {
result = a->handleKeyDown(&npEvent->data.keyEvent);
break;
}
case (npPalmKeyUpEvent): {
result = a->handleKeyUp(&npEvent->data.keyEvent);
break;
}
case (npPalmTouchStartEvent): {
result = a->handleTouchStart(&npEvent->data.touchEvent);
break;
}
case (npPalmTouchMoveEvent): {
result = a->handleTouchMove(&npEvent->data.touchEvent);
break;
}
case (npPalmTouchEndEvent): {
result = a->handleTouchEnd(&npEvent->data.touchEvent);
break;
}
case (npPalmTouchCancelledEvent): {
result = a->handleTouchCancelled(&npEvent->data.touchEvent);
break;
}
case (npPalmGestureEvent): {
NpPalmGestureEvent gestureEvent = npEvent->data.gestureEvent;
gestureEvent.x -= a->mWindow.x;
gestureEvent.y -= a->mWindow.y;
gestureEvent.center_x -= a->mWindow.x;
gestureEvent.center_y -= a->mWindow.y;
result = a->handleGesture(&gestureEvent);
break;
}
case (npPalmSystemEvent): {
NpPalmSystemEvent systemEvent = npEvent->data.systemEvent;
switch (systemEvent.type) {
case (npPalmGainFocusEvent):
result = a->handleFocus(true);
break;
case (npPalmLoseFocusEvent):
result = a->handleFocus(false);
break;
default:
break;
}
}
default:
break;
}
// TRACE("returning handled=%d", (int)result);
return result;
}
/* Unimplemented. */
void AdapterBase::PrvNPP_UrlNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
{
return;
}
/*
Called by webkit to look up instance specific property values.
Currently used only for scripting integration.
*/
NPError AdapterBase::PrvNPP_GetValue(NPP instance, NPPVariable variable, void *retValue)
{
AdapterBase *a = (AdapterBase*)instance->pdata;
const char* *names = NULL;
NPObject *obj = NULL;
if (a == NULL)
return NPERR_INVALID_PARAM;
bool handled = true;
switch (static_cast<int>(variable)) {
case NPPVpluginNameString:
static const char* sName = "Palm Native Adapter";
*((char**) retValue) = const_cast<char*>(sName);
break;
case NPPVpluginDescriptionString:
static const char* sDesc = "Palm Adapter to native service";
*((char**) retValue) = const_cast<char*>(sDesc);
break;
case NPPVpluginScriptableNPObject:
// start with the member version
a->mJSMethodCount = a->adapterGetMethods(&names, &a->mJSMethods, &a->mJSIdentifiers);
// if the internal had nothing to say, use the c-api version
if ( a->mJSMethodCount <= 0 )
{
a->mJSMethodCount = AdapterGetMethods(&names, &a->mJSMethods, &a->mJSIdentifiers);
}
// If we're not scriptable, then we fail to return the "scriptable object" value to the host browser.
if(a->mJSMethodCount <= 0 || a->mJSIdentifiers == NULL || names == NULL || a->mJSMethods == NULL) {
handled = false;
break;
}
// If the method IDs array hasn't been filled out yet, then do that:
if(a->mJSIdentifiers[0] == NULL)
sBrowserFuncs.getstringidentifiers(names, a->mJSMethodCount, a->mJSIdentifiers);
// Create the "scriptable object" for this instance:
if (a->mNPObject == NULL)
obj = a->NPN_CreateObject(&sPluginClass);
// The return value from NPN_CreateObject should be the same
// as the value returned by our PrvObjAllocate() implementation.
if(obj != (NPObject*)(a->mNPObject)) {
fprintf(stderr, "obj != a->mNPObject, go check everything!");
}
a->NPN_RetainObject((NPObject*)a->mNPObject);
*((NPObject**) retValue) = (NPObject*)a->mNPObject;
break;
case npPalmCachePluginValue:
*reinterpret_cast<bool*>(retValue) = a->mCacheAdapter;
break;
case npPalmUseGraphicsContext:
*reinterpret_cast<bool*>(retValue) = a->mUseGraphicsContext;
break;
default:
handled = false;
}
if (!handled)
return NPERR_INVALID_PARAM;
return NPERR_NO_ERROR;
}
uint32_t AdapterBase::adapterGetMethods(const char*** outNames, const JSMethodPtr **outMethods, NPIdentifier **outIDs)
{
return 0;
}
/*
Called by webkit to inform the plugin instance about the GMainLoop it will be running under.
Probably called in other instances too, but we ignore them for now. ;-D
*/
NPError AdapterBase::PrvNPP_SetValue(NPP instance, NPNVariable variable, void *value)
{
// TRACE("type=%d", variable);
if (!instance) {
return NPERR_INVALID_PARAM;
}
// We must allow a NULL adapter instance when setting the event loop,
// since that's actually when we *allocate* the adapter instance.
if(instance->pdata == NULL && variable != (NPNVariable)npPalmEventLoopValue) {
fprintf(stderr, "WARNING - %s called with NULL adapter instance.\n", __FUNCTION__);
return NPERR_GENERIC_ERROR;
}
switch (static_cast<int>(variable)) {
case (npPalmEventLoopValue): {
GMainLoop* mainLoop = (GMainLoop*) value;
AdapterBase* a;
// Event loop has been set, so create the Adapter instance if it hasn't been created already.
if(instance->pdata == NULL) {
a = AdapterCreate(instance, mainLoop, gArgc, gArgn, gArgv);
if (a == NULL) {
return NPERR_GENERIC_ERROR;
}
// free saved arguments:
gArgc = 0;
PrvFreeArgv(gArgn);
PrvFreeArgv(gArgv);
gArgn = NULL;
gArgv = NULL;
}
// Set the loop in the instance too:
a = (AdapterBase*)instance->pdata;
a->mMainLoop = mainLoop;
break;
}
default:
break;
}
return NPERR_NO_ERROR;
}
int AdapterBase::GetScreenResolution(int& hres, int &vres)
{
hres = 320;
vres = 480;
int err(0);
#if defined(__arm__)
int fbfd(-1);
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
fbfd = open("/dev/fb0", O_RDWR);
if (-1 == fbfd) {
TRACE("Error: cannot open framebuffer device");
err = errno;
}
// Get fixed screen information
if (!err) {
err = ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo);
if (err) {
TRACE("Error reading fixed info.");
}
}
// Get variable screen information
if (!err) {
err = ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo);
if (err) {
TRACE("Error reading variable info.");
}
else {
TRACE("%dx%d, %dbpp", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
hres = vinfo.xres;
vres = vinfo.yres;
}
}
if (fbfd != -1) {
close(fbfd);
}
#endif
return err;
}
// -----------------------------------------------------------------------------------
// Static NPN Object hook implementations.
// These are set up to expose AdapterBase objects as scriptable JavaScript objects.
// This handles generic method dispatch, and management of the AdapterBase object lifetime.
// The actual behavior of particular methods is of course handled by the adapter author.
// -----------------------------------------------------------------------------------
/*
Called to allocate the scriptable object for an adapter plugin instance
*/
NPObject* AdapterBase::PrvObjAllocate(NPP npp, NPClass* klass)
{
// We allocate only a small placeholder object for the NPObject required for JS scripting integration.
// This complicates things slightly in some ways, since this separate object is reference counted &
// garbage collected, whereas the plugin instance is explicitly deleted. We set things up so that the
// lifetime of the AdapterBase is whichever is longer, and then we can route all NSObject scripting related
// calls to the AdapterBase, providing a unified interface for adapter authors.
AdapterBase* a = (AdapterBase*) npp->pdata;
if(a == NULL) return NULL;
// This should be safe since AFAIK only we can allocate NPObjects of our class.
a->mNPObject = (AdapterNPObj*)malloc(sizeof(AdapterNPObj));
a->mNPObject->adapter = a;
return (NPObject*)a->mNPObject;
}
/*
Called to deallocate the scriptable object assiciated with a plugin instance, when its refcount reaches zero.
(Or else sometime after that, when the object is garbage collected).
*/
void AdapterBase::PrvObjDeallocate(NPObject* obj)
{
AdapterBase *a = ((AdapterNPObj*)obj)->adapter;
if(obj != (NPObject*)a->mNPObject) {
// This should never happen.
fprintf(stderr, "WARNING: AdapterBase::PrvObjDeallocate: obj != a->mNPObject, adapter may be leaked.\n");
return;
}
// First deallocate our little placeholder object, and clear out the reference to it:
free(obj);
a->mNPObject = NULL;
// Next, if the plugin instance has already been destroyed,
// then we can deallocate the AdapterBase as well.
// If it's not deleted here, then it should happen in PrvNPP_Destroy().
if(a->mInstance == NULL)
{
delete a;
}
return;
}
void AdapterBase::PrvObjInvalidate(NPObject* obj)
{
fprintf(stderr, "AdapterBase::PrvObjInvalidate: UNIMPLEMENTED\n");
}
/**
* Called by webkit to find out if our object has a native implementation for the given method.
*/
bool AdapterBase::PrvObjHasMethod(NPObject* obj, NPIdentifier name)
{
AdapterBase *a = ((AdapterNPObj*)obj)->adapter;
return a->PrvFindMethod(name) != NULL;
}
/**
* Called by webkit to invoke a native method on our object from JavaScript.
*/
bool AdapterBase::PrvObjInvoke(NPObject *obj, NPIdentifier name,
const NPVariant *args, uint32_t argCount, NPVariant *result)
{
AdapterBase *a = ((AdapterNPObj*)obj)->adapter;
return a->doPrvObjInvoke(obj, name, args, argCount, result);
}
bool AdapterBase::doPrvObjInvoke(NPObject *obj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
// See if we implement this method:
JSMethodPtr method = PrvFindMethod(name);
if(method == NULL) return false;
// If so, call it.
const char* errorMsg = (method)(this, args, argCount, result);
// Set exception & report error message if something bad happened.
if(errorMsg != NULL)
sBrowserFuncs.setexception(mDOMObject, errorMsg);
return true;
}
bool AdapterBase::PrvObjInvokeDefault(NPObject *obj, const NPVariant *args,
uint32_t argCount, NPVariant *result)
{
fprintf(stderr, "AdapterBase::PrvObjInvokeDefault: UNIMPLEMENTED\n");
return false;
}
bool AdapterBase::PrvObjHasProperty(NPObject *obj, NPIdentifier name)
{
// We don't support any properties.
return false;
}
bool AdapterBase::PrvObjGetProperty(NPObject *obj, NPIdentifier name, NPVariant *result)
{
fprintf(stderr, "AdapterBase::PrvObjGetProperty: UNIMPLEMENTED\n");
return false;
}
bool AdapterBase::PrvObjSetProperty(NPObject *obj, NPIdentifier name, const NPVariant *value)
{
fprintf(stderr, "AdapterBase::PrvObjSetProperty: UNIMPLEMENTED\n");
return false;
}
bool AdapterBase::PrvObjRemoveProperty(NPObject *obj, NPIdentifier name)
{
fprintf(stderr, "AdapterBase::PrvObjRemoveProperty: UNIMPLEMENTED\n");
return false;
}
bool AdapterBase::PrvObjEnumerate(NPObject *obj, NPIdentifier **value, uint32_t *count)
{
fprintf(stderr, "AdapterBase::PrvObjEnumerate: UNIMPLEMENTED\n");
return false;
}
bool AdapterBase::PrvObjConstruct(NPObject *obj, const NPVariant *args,
uint32_t argCount, NPVariant *result)
{
fprintf(stderr, "AdapterBase::PrvObjConstruct: UNIMPLEMENTED\n");
return false;
}
// -----------------------------------------------------------------------------------
// NPN API Shims
// These are local equivalents of the browser-implemented NPN APIs.
// They handle passing in the appropriate NPP instance when needed,
// and provide more API-like calling behavior than directly accessing sBrowserFuncs.
// For Luna 2.0, we plan to have only a single adapter implementation on the native side,
// which services can interact with to display their data, and this goal is eased somewhat
// by limiting current adapter implementations to critical APIs only.
// -----------------------------------------------------------------------------------
void AdapterBase::NPN_InvalidateRect(NPRect *invalidRect)
{
sBrowserFuncs.invalidaterect(mInstance, invalidRect);
}
NPIdentifier AdapterBase::NPN_GetStringIdentifier(const char* utf8)
{
return sBrowserFuncs.getstringidentifier(utf8);
}
void AdapterBase::NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount,
NPIdentifier *identifiers)
{
return sBrowserFuncs.getstringidentifiers(names, nameCount, identifiers);
}
NPUTF8 *AdapterBase::NPN_UTF8FromIdentifier(NPIdentifier identifier)
{
return sBrowserFuncs.utf8fromidentifier(identifier);
}
NPObject* AdapterBase::NPN_CreateObject(NPClass *aClass)
{
return sBrowserFuncs.createobject(mInstance, aClass);
}
NPObject* AdapterBase::NPN_RetainObject(NPObject *npobj)
{
return sBrowserFuncs.retainobject(npobj);
}
void AdapterBase::NPN_ReleaseObject(NPObject *npobj)
{
return sBrowserFuncs.releaseobject(npobj);
}
void AdapterBase::NPN_ReleaseVariantValue(NPVariant *variant)
{
return sBrowserFuncs.releasevariantvalue(variant);
}
bool AdapterBase::NPN_InvokeDefault(NPObject *obj, const NPVariant *args, uint32_t argCount, NPVariant *result)
{
return sBrowserFuncs.invokeDefault(mInstance, obj, args, argCount, result);
}
void* AdapterBase::NPN_GetValue(NPNVariable variable)
{
void* res = 0;
if (sBrowserFuncs.getvalue(mInstance, variable, &res) != NPERR_NO_ERROR)
return 0;
return res;
}
NPError AdapterBase::NPN_SetValue(NPPVariable variable, void* value)
{
if (!sBrowserFuncs.setvalue)
return NPERR_GENERIC_ERROR;
return sBrowserFuncs.setvalue(mInstance, variable, value);
}
NPError AdapterBase::NPN_GetURL(const char* url, const char* target)
{
return sBrowserFuncs.geturl(mInstance, url, target);
}
void AdapterBase::SetAdapterName( const char* name )
{
if (name != NULL) {
strncpy( g_szAdapterName, name, sizeof(g_szAdapterName)-1 );
g_szAdapterName[sizeof(g_szAdapterName)-1] = '\0';
}
}
void AdapterBase::SetAdapterDescription( const char* desc )
{
if (desc != NULL) {
strncpy( g_szAdapterDescription, desc, sizeof(g_szAdapterDescription)-1 );
g_szAdapterDescription[sizeof(g_szAdapterDescription)-1] = '\0';
}
}
// stubs for multitouch support.
bool AdapterBase::handleTouchStart(NpPalmTouchEvent *event) {
return true;
}
bool AdapterBase::handleTouchMove(NpPalmTouchEvent *event) {
return true;
}
bool AdapterBase::handleTouchEnd(NpPalmTouchEvent *event) {
return true;
}
bool AdapterBase::handleTouchCancelled(NpPalmTouchEvent *event) {
return true;
}
bool AdapterBase::handleGesture(NpPalmGestureEvent *event) {
return true;
}