From a6cb8553d35c4fe45b52aa425392c1b5b0fc094a Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Wed, 5 Aug 2009 15:36:33 -0700 Subject: [PATCH] Add test plugin for ipc, make sure it works --- dom/plugins/Makefile.in | 2 + dom/plugins/NPAPIPluginParent.h | 2 +- dom/plugins/testplugin/Info.plist | 38 ++ dom/plugins/testplugin/Makefile.in | 99 ++++ dom/plugins/testplugin/npipctest.cpp | 516 +++++++++++++++++++ dom/plugins/testplugin/npipctest.def | 7 + dom/plugins/testplugin/npipctest.h | 62 +++ dom/plugins/testplugin/npipctest.rc | 42 ++ dom/plugins/testplugin/npipctest_gtk2.cpp | 498 ++++++++++++++++++ dom/plugins/testplugin/npipctest_macosx.mm | 290 +++++++++++ dom/plugins/testplugin/npipctest_os2.cpp | 93 ++++ dom/plugins/testplugin/npipctest_platform.h | 116 +++++ dom/plugins/testplugin/npipctest_qt.cpp | 93 ++++ dom/plugins/testplugin/npipctest_utils.cpp | 119 +++++ dom/plugins/testplugin/npipctest_utils.h | 45 ++ dom/plugins/testplugin/npipctest_windows.cpp | 406 +++++++++++++++ ipc/glue/IPCMessageUtils.h | 27 +- 17 files changed, 2438 insertions(+), 17 deletions(-) create mode 100644 dom/plugins/testplugin/Info.plist create mode 100644 dom/plugins/testplugin/Makefile.in create mode 100644 dom/plugins/testplugin/npipctest.cpp create mode 100644 dom/plugins/testplugin/npipctest.def create mode 100644 dom/plugins/testplugin/npipctest.h create mode 100644 dom/plugins/testplugin/npipctest.rc create mode 100644 dom/plugins/testplugin/npipctest_gtk2.cpp create mode 100644 dom/plugins/testplugin/npipctest_macosx.mm create mode 100644 dom/plugins/testplugin/npipctest_os2.cpp create mode 100644 dom/plugins/testplugin/npipctest_platform.h create mode 100644 dom/plugins/testplugin/npipctest_qt.cpp create mode 100644 dom/plugins/testplugin/npipctest_utils.cpp create mode 100644 dom/plugins/testplugin/npipctest_utils.h create mode 100644 dom/plugins/testplugin/npipctest_windows.cpp diff --git a/dom/plugins/Makefile.in b/dom/plugins/Makefile.in index 6ea6281ef92b..4e334079d5e4 100644 --- a/dom/plugins/Makefile.in +++ b/dom/plugins/Makefile.in @@ -44,6 +44,8 @@ include $(DEPTH)/config/autoconf.mk MODULE = dom +DIRS += testplugin + EXPORTS_NAMESPACES = mozilla EXPORTS_mozilla = \ diff --git a/dom/plugins/NPAPIPluginParent.h b/dom/plugins/NPAPIPluginParent.h index ad3e850b0c5e..2b2562ca6054 100644 --- a/dom/plugins/NPAPIPluginParent.h +++ b/dom/plugins/NPAPIPluginParent.h @@ -533,7 +533,7 @@ private: return (symbol_type) NP_GetMIMEDescription; if (!strcmp("NP_GetValue", aSymbolName)) return (symbol_type) NP_GetValue; -#ifdef OS_WINDOWS +#ifdef OS_WIN if (!strcmp("NP_GetEntryPoints", aSymbolName)) return (symbol_type) NP_GetEntryPoints; #endif diff --git a/dom/plugins/testplugin/Info.plist b/dom/plugins/testplugin/Info.plist new file mode 100644 index 000000000000..0938bc0f4b19 --- /dev/null +++ b/dom/plugins/testplugin/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + libnpipctest.dylib + CFBundleIdentifier + org.mozilla.TestIPCPlugin + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BRPL + CFBundleShortVersionString + 1.0.0.0 + CFBundleSignature + TEST + CFBundleVersion + 1.0.0.0 + WebPluginName + Test Plug-in for IPC + WebPluginDescription + Plug-in for IPC testing purposes. + WebPluginMIMETypes + + application/x-test-ipc + + WebPluginExtensions + + tstipc + + WebPluginTypeDescription + Test IPC mimetype + + + + diff --git a/dom/plugins/testplugin/Makefile.in b/dom/plugins/testplugin/Makefile.in new file mode 100644 index 000000000000..904b05c5747f --- /dev/null +++ b/dom/plugins/testplugin/Makefile.in @@ -0,0 +1,99 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (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.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is mozilla.org +# Portions created by the Initial Developer are Copyright (C) 2008 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Dave Townsend +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = npipctest +LIBRARY_NAME = npipctest +MODULE_NAME = TestIPCPlugin + +# Need to custom install plugins +NO_DIST_INSTALL = 1 +NO_INSTALL = 1 + +CPPSRCS = \ + npipctest.cpp \ + npipctest_utils.cpp \ + $(NULL) + +ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) +CMMSRCS = npipctest_macosx.mm +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) +CPPSRCS += npipctest_gtk2.cpp +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),os2) +CPPSRCS += npipctest_os2.cpp +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),qt) +CPPSRCS += npipctest_qt.cpp +endif + +ifeq ($(MOZ_WIDGET_TOOLKIT),windows) +CPPSRCS += npipctest_windows.cpp +RCFILE = npipctest.rc +RESFILE = npipctest.res +DEFFILE = $(win_srcdir)/npipctest.def +endif + +include $(topsrcdir)/config/rules.mk + +ifeq ($(MOZ_WIDGET_TOOLKIT),gtk2) +CXXFLAGS += $(MOZ_GTK2_CFLAGS) +CFLAGS += $(MOZ_GTK2_CFLAGS) +EXTRA_DSO_LDOPTS += $(MOZ_GTK2_LIBS) $(XLDFLAGS) $(XLIBS) $(XEXT_LIBS) +endif + +install-plugin: $(SHARED_LIBRARY) +ifdef SHARED_LIBRARY +ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa) + $(INSTALL) $(srcdir)/Info.plist $(DIST)/bin/plugins/Test.plugin/Contents + $(INSTALL) $(SHARED_LIBRARY) $(DIST)/bin/plugins/Test.plugin/Contents/MacOS +else + $(INSTALL) $(SHARED_LIBRARY) $(DIST)/bin/plugins +endif +endif + +libs:: install-plugin diff --git a/dom/plugins/testplugin/npipctest.cpp b/dom/plugins/testplugin/npipctest.cpp new file mode 100644 index 000000000000..9121529dffcb --- /dev/null +++ b/dom/plugins/testplugin/npipctest.cpp @@ -0,0 +1,516 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Dave Townsend + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest.h" +#include "npipctest_utils.h" +#include "npipctest_platform.h" + +#include +#include +#include + +#define PLUGIN_NAME "Test IPC Plug-in" +#define PLUGIN_DESCRIPTION "Plug-in for IPC testing purposes." +#define PLUGIN_VERSION "1.0.0.0" + +// +// static data +// + +static NPNetscapeFuncs* sBrowserFuncs = NULL; +static NPClass sNPClass; + +// +// function signatures +// + +NPObject* scriptableAllocate(NPP npp, NPClass* aClass); +void scriptableDeallocate(NPObject* npobj); +void scriptableInvalidate(NPObject* npobj); +bool scriptableHasMethod(NPObject* npobj, NPIdentifier name); +bool scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result); +bool scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +bool scriptableHasProperty(NPObject* npobj, NPIdentifier name); +bool scriptableGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result); +bool scriptableSetProperty(NPObject* npobj, NPIdentifier name, const NPVariant* value); +bool scriptableRemoveProperty(NPObject* npobj, NPIdentifier name); +bool scriptableEnumerate(NPObject* npobj, NPIdentifier** identifier, uint32_t* count); +bool scriptableConstruct(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); + +// +// npapi plugin functions +// + +#ifdef XP_UNIX +NP_EXPORT(char*) +NP_GetPluginVersion() +{ + return PLUGIN_VERSION; +} +#endif + +#if defined(XP_UNIX) +NP_EXPORT(char*) NP_GetMIMEDescription() +#elif defined(XP_WIN) || defined(XP_OS2) +char* NP_GetMIMEDescription() +#endif +{ + return "application/x-test-ipc:tstipc:Test IPC mimetype"; +} + +#ifdef XP_UNIX +NP_EXPORT(NPError) +NP_GetValue(void* future, NPPVariable aVariable, void* aValue) { + switch (aVariable) { + case NPPVpluginNameString: + *((char**)aValue) = PLUGIN_NAME; + break; + case NPPVpluginDescriptionString: + *((char**)aValue) = PLUGIN_DESCRIPTION; + break; + default: + return NPERR_INVALID_PARAM; + break; + } + return NPERR_NO_ERROR; +} +#endif + +static void fillPluginFunctionTable(NPPluginFuncs* pFuncs) +{ + pFuncs->version = 11; + pFuncs->size = sizeof(*pFuncs); + pFuncs->newp = NPP_New; + pFuncs->destroy = NPP_Destroy; + pFuncs->setwindow = NPP_SetWindow; + pFuncs->newstream = NPP_NewStream; + pFuncs->destroystream = NPP_DestroyStream; + pFuncs->asfile = NPP_StreamAsFile; + pFuncs->writeready = NPP_WriteReady; + pFuncs->write = NPP_Write; + pFuncs->print = NPP_Print; + pFuncs->event = NPP_HandleEvent; + pFuncs->urlnotify = NPP_URLNotify; + pFuncs->getvalue = NPP_GetValue; + pFuncs->setvalue = NPP_SetValue; +} + +#if defined(XP_MACOSX) +NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs) +#elif defined(XP_WIN) || defined(XP_OS2) +NPError OSCALL NP_Initialize(NPNetscapeFuncs* bFuncs) +#elif defined(XP_UNIX) +NP_EXPORT(NPError) NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs) +#endif +{ + sBrowserFuncs = bFuncs; + + memset(&sNPClass, 0, sizeof(NPClass)); + sNPClass.structVersion = NP_CLASS_STRUCT_VERSION; + sNPClass.allocate = (NPAllocateFunctionPtr)scriptableAllocate; + sNPClass.deallocate = (NPDeallocateFunctionPtr)scriptableDeallocate; + sNPClass.invalidate = (NPInvalidateFunctionPtr)scriptableInvalidate; + sNPClass.hasMethod = (NPHasMethodFunctionPtr)scriptableHasMethod; + sNPClass.invoke = (NPInvokeFunctionPtr)scriptableInvoke; + sNPClass.invokeDefault = (NPInvokeDefaultFunctionPtr)scriptableInvokeDefault; + sNPClass.hasProperty = (NPHasPropertyFunctionPtr)scriptableHasProperty; + sNPClass.getProperty = (NPGetPropertyFunctionPtr)scriptableGetProperty; + sNPClass.setProperty = (NPSetPropertyFunctionPtr)scriptableSetProperty; + sNPClass.removeProperty = (NPRemovePropertyFunctionPtr)scriptableRemoveProperty; + sNPClass.enumerate = (NPEnumerationFunctionPtr)scriptableEnumerate; + sNPClass.construct = (NPConstructFunctionPtr)scriptableConstruct; + +#if defined(XP_UNIX) && !defined(XP_MACOSX) + fillPluginFunctionTable(pFuncs); +#endif + + return NPERR_NO_ERROR; +} + +#if defined(XP_MACOSX) +NP_EXPORT(NPError) NP_GetEntryPoints(NPPluginFuncs* pFuncs) +#elif defined(XP_WIN) || defined(XP_OS2) +NPError OSCALL NP_GetEntryPoints(NPPluginFuncs* pFuncs) +#endif +#if defined(XP_MACOSX) || defined(XP_WIN) || defined(XP_OS2) +{ + fillPluginFunctionTable(pFuncs); + return NPERR_NO_ERROR; +} +#endif + +#if defined(XP_UNIX) +NP_EXPORT(NPError) NP_Shutdown() +#elif defined(XP_WIN) || defined(XP_OS2) +NPError OSCALL NP_Shutdown() +#endif +{ + return NPERR_NO_ERROR; +} + +NPError +NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* argn[], char* argv[], NPSavedData* saved) +{ + // Make sure we can render this plugin + NPBool browserSupportsWindowless = false; + NPN_GetValue(instance, NPNVSupportsWindowless, &browserSupportsWindowless); + if (!browserSupportsWindowless && !pluginSupportsWindowMode()) { + printf("Windowless mode not supported by the browser, windowed mode not supported by the plugin!\n"); + return NPERR_GENERIC_ERROR; + } + + // set up our our instance data + InstanceData* instanceData = (InstanceData*)malloc(sizeof(InstanceData)); + if (!instanceData) + return NPERR_OUT_OF_MEMORY_ERROR; + memset(instanceData, 0, sizeof(InstanceData)); + instanceData->npp = instance; + instance->pdata = instanceData; + + bool requestWindow = true; + + if (!browserSupportsWindowless || !pluginSupportsWindowlessMode()) { + requestWindow = true; + } else if (!pluginSupportsWindowMode()) { + requestWindow = false; + } + if (requestWindow) { + instanceData->hasWidget = true; + } else { + // NPPVpluginWindowBool should default to true, so we may as well + // test that by not setting it in the window case + NPN_SetValue(instance, NPPVpluginWindowBool, (void*)false); + } + + instanceData->lastReportedPrivateModeState = false; + + // do platform-specific initialization + NPError err = pluginInstanceInit(instanceData); + if (err != NPERR_NO_ERROR) { + free(instanceData); + return err; + } + + return NPERR_NO_ERROR; +} + +NPError +NPP_Destroy(NPP instance, NPSavedData** save) +{ + InstanceData* instanceData = (InstanceData*)(instance->pdata); + pluginInstanceShutdown(instanceData); + free(instanceData); + + return NPERR_NO_ERROR; +} + +NPError +NPP_SetWindow(NPP instance, NPWindow* window) +{ + InstanceData* instanceData = (InstanceData*)(instance->pdata); + void* oldWindow = instanceData->window.window; + pluginDoSetWindow(instanceData, window); + if (instanceData->hasWidget && oldWindow != instanceData->window.window) { + pluginWidgetInit(instanceData, oldWindow); + } + return NPERR_NO_ERROR; +} + +NPError +NPP_NewStream(NPP instance, NPMIMEType type, NPStream* stream, NPBool seekable, uint16_t* stype) +{ + *stype = NP_ASFILEONLY; + return NPERR_NO_ERROR; +} + +NPError +NPP_DestroyStream(NPP instance, NPStream* stream, NPReason reason) +{ + return NPERR_NO_ERROR; +} + +int32_t +NPP_WriteReady(NPP instance, NPStream* stream) +{ + return 0; +} + +int32_t +NPP_Write(NPP instance, NPStream* stream, int32_t offset, int32_t len, void* buffer) +{ + return 0; +} + +void +NPP_StreamAsFile(NPP instance, NPStream* stream, const char* fname) +{ +} + +void +NPP_Print(NPP instance, NPPrint* platformPrint) +{ +} + +int16_t +NPP_HandleEvent(NPP instance, void* event) +{ + InstanceData* instanceData = (InstanceData*)(instance->pdata); + return pluginHandleEvent(instanceData, event); +} + +void +NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData) +{ +} + +NPError +NPP_GetValue(NPP instance, NPPVariable variable, void* value) +{ + InstanceData* instanceData = (InstanceData*)instance->pdata; + if (variable == NPPVpluginNeedsXEmbed) { + // Only relevant for X plugins + *(NPBool*)value = instanceData->hasWidget; + return NPERR_NO_ERROR; + } + + return NPERR_GENERIC_ERROR; +} + +NPError +NPP_SetValue(NPP instance, NPNVariable variable, void* value) +{ + if (variable == NPNVprivateModeBool) { + InstanceData* instanceData = (InstanceData*)(instance->pdata); + instanceData->lastReportedPrivateModeState = bool(*static_cast(value)); + return NPERR_NO_ERROR; + } + return NPERR_GENERIC_ERROR; +} + +// +// npapi browser functions +// + +bool +NPN_SetProperty(NPP instance, NPObject* obj, NPIdentifier propertyName, const NPVariant* value) +{ + return sBrowserFuncs->setproperty(instance, obj, propertyName, value); +} + +NPIdentifier +NPN_GetIntIdentifier(int32_t intid) +{ + return sBrowserFuncs->getintidentifier(intid); +} + +NPIdentifier +NPN_GetStringIdentifier(const NPUTF8* name) +{ + return sBrowserFuncs->getstringidentifier(name); +} + +void +NPN_GetStringIdentifiers(const NPUTF8 **names, int32_t nameCount, NPIdentifier *identifiers) +{ + return sBrowserFuncs->getstringidentifiers(names, nameCount, identifiers); +} + +NPUTF8* +NPN_UTF8FromIdentifier(NPIdentifier identifier) +{ + return sBrowserFuncs->utf8fromidentifier(identifier); +} + +int32_t +NPN_IntFromIdentifier(NPIdentifier identifier) +{ + return sBrowserFuncs->intfromidentifier(identifier); +} + +NPError +NPN_GetValue(NPP instance, NPNVariable variable, void* value) +{ + return sBrowserFuncs->getvalue(instance, variable, value); +} + +NPError +NPN_SetValue(NPP instance, NPPVariable variable, void* value) +{ + return sBrowserFuncs->setvalue(instance, variable, value); +} + +bool +NPN_HasProperty(NPP instance, NPObject* obj, NPIdentifier propertyName) +{ + return sBrowserFuncs->hasproperty(instance, obj, propertyName); +} + +NPObject* +NPN_CreateObject(NPP instance, NPClass* aClass) +{ + return sBrowserFuncs->createobject(instance, aClass); +} + +bool +NPN_Invoke(NPP npp, NPObject* obj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + return sBrowserFuncs->invoke(npp, obj, methodName, args, argCount, result); +} + +const char* +NPN_UserAgent(NPP instance) +{ + return sBrowserFuncs->uagent(instance); +} + +NPObject* +NPN_RetainObject(NPObject* obj) +{ + return sBrowserFuncs->retainobject(obj); +} + +void +NPN_ReleaseObject(NPObject* obj) +{ + return sBrowserFuncs->releaseobject(obj); +} + +void* +NPN_MemAlloc(uint32_t size) +{ + return sBrowserFuncs->memalloc(size); +} + +void +NPN_MemFree(void* ptr) +{ + return sBrowserFuncs->memfree(ptr); +} + +uint32_t +NPN_ScheduleTimer(NPP instance, uint32_t interval, NPBool repeat, void (*timerFunc)(NPP npp, uint32_t timerID)) +{ + return sBrowserFuncs->scheduletimer(instance, interval, repeat, timerFunc); +} + +void +NPN_UnscheduleTimer(NPP instance, uint32_t timerID) +{ + return sBrowserFuncs->unscheduletimer(instance, timerID); +} + +void +NPN_ReleaseVariantValue(NPVariant *variant) +{ + return sBrowserFuncs->releasevariantvalue(variant); +} + +// +// npruntime object functions +// + +NPObject* +scriptableAllocate(NPP npp, NPClass* aClass) +{ + NPObject* object = (NPObject*)NPN_MemAlloc(sizeof(NPObject)); + if (!object) + return NULL; + memset(object, 0, sizeof(NPObject)); + return object; +} + +void +scriptableDeallocate(NPObject* npobj) +{ + NPN_MemFree(npobj); +} + +void +scriptableInvalidate(NPObject* npobj) +{ +} + +bool +scriptableHasMethod(NPObject* npobj, NPIdentifier name) +{ + return false; +} + +bool +scriptableInvoke(NPObject* npobj, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return false; +} + +bool +scriptableInvokeDefault(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return false; +} + +bool +scriptableHasProperty(NPObject* npobj, NPIdentifier name) +{ + return false; +} + +bool +scriptableGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result) +{ + return false; +} + +bool +scriptableSetProperty(NPObject* npobj, NPIdentifier name, const NPVariant* value) +{ + return false; +} + +bool +scriptableRemoveProperty(NPObject* npobj, NPIdentifier name) +{ + return false; +} + +bool +scriptableEnumerate(NPObject* npobj, NPIdentifier** identifier, uint32_t* count) +{ + return false; +} + +bool +scriptableConstruct(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return false; +} diff --git a/dom/plugins/testplugin/npipctest.def b/dom/plugins/testplugin/npipctest.def new file mode 100644 index 000000000000..c6caf169fc16 --- /dev/null +++ b/dom/plugins/testplugin/npipctest.def @@ -0,0 +1,7 @@ +LIBRARY NPIPCTEST + +EXPORTS + NP_GetEntryPoints @1 + NP_Initialize @2 + NP_Shutdown @3 + NP_GetMIMEDescription @4 diff --git a/dom/plugins/testplugin/npipctest.h b/dom/plugins/testplugin/npipctest.h new file mode 100644 index 000000000000..dec8855fc1ea --- /dev/null +++ b/dom/plugins/testplugin/npipctest.h @@ -0,0 +1,62 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nptest_h_ +#define nptest_h_ + +#include "mozilla-config.h" + +#include "npapi.h" +#include "npfunctions.h" +#include "npruntime.h" +#include "prtypes.h" + +typedef enum { + DM_DEFAULT, + DM_SOLID_COLOR +} DrawMode; + +typedef struct _PlatformData PlatformData; + +typedef struct InstanceData { + NPP npp; + NPWindow window; + PlatformData* platformData; + uint32_t instanceCountWatchGeneration; + bool lastReportedPrivateModeState; + bool hasWidget; + uint32_t timerID1; + uint32_t timerID2; +} InstanceData; + +#endif // nptest_h_ diff --git a/dom/plugins/testplugin/npipctest.rc b/dom/plugins/testplugin/npipctest.rc new file mode 100644 index 000000000000..fc4270e3ea14 --- /dev/null +++ b/dom/plugins/testplugin/npipctest.rc @@ -0,0 +1,42 @@ +#include + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "mozilla.org" + VALUE "FileDescription", "Plug-in for IPC testing purposes." + VALUE "FileExtents", "tstipc" + VALUE "FileOpenName", "Test IPC mimetype" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "npipctest" + VALUE "MIMEType", "application/x-test-ipc" + VALUE "OriginalFilename", "npipctest.dll" + VALUE "ProductName", "Test IPC Plug-in" + VALUE "ProductVersion", "1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END diff --git a/dom/plugins/testplugin/npipctest_gtk2.cpp b/dom/plugins/testplugin/npipctest_gtk2.cpp new file mode 100644 index 000000000000..1a83769b0c1c --- /dev/null +++ b/dom/plugins/testplugin/npipctest_gtk2.cpp @@ -0,0 +1,498 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * Michael Ventnor + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest_platform.h" +#include "npapi.h" +#include +#ifdef MOZ_X11 +#include +#include +#endif +#include + +/** + * XXX In various places in this file we use GDK APIs to inspect the + * window ancestors of the plugin. These APIs will not work properly if + * this plugin is used in a browser that does not use GDK for all its + * widgets. They would also fail for out-of-process plugins. These should + * be fixed to use raw X APIs instead. + */ + +struct _PlatformData { + Display* display; + GtkWidget* plug; +}; + +bool +pluginSupportsWindowMode() +{ + return true; +} + +bool +pluginSupportsWindowlessMode() +{ + return true; +} + +NPError +pluginInstanceInit(InstanceData* instanceData) +{ +#ifdef MOZ_X11 + instanceData->platformData = static_cast + (NPN_MemAlloc(sizeof(PlatformData))); + if (!instanceData->platformData) + return NPERR_OUT_OF_MEMORY_ERROR; + + instanceData->platformData->display = 0; + instanceData->platformData->plug = 0; + + return NPERR_NO_ERROR; +#else + // we only support X11 here, since thats what the plugin system uses + return NPERR_INCOMPATIBLE_VERSION_ERROR; +#endif +} + +void +pluginInstanceShutdown(InstanceData* instanceData) +{ + if (instanceData->hasWidget) { + Window window = reinterpret_cast(instanceData->window.window); + + if (window != None) { + // This window XID should still be valid. + // See bug 429604 and bug 454756. + XWindowAttributes attributes; + if (!XGetWindowAttributes(instanceData->platformData->display, window, + &attributes)) + g_error("XGetWindowAttributes failed at plugin instance shutdown"); + } + } + + GtkWidget* plug = instanceData->platformData->plug; + if (plug) { + instanceData->platformData->plug = 0; + gtk_widget_destroy(plug); + } + + NPN_MemFree(instanceData->platformData); + instanceData->platformData = 0; +} + +static void +SetCairoRGBA(cairo_t* cairoWindow, PRUint32 rgba) +{ + float b = (rgba & 0xFF) / 255.0; + float g = ((rgba & 0xFF00) >> 8) / 255.0; + float r = ((rgba & 0xFF0000) >> 16) / 255.0; + float a = ((rgba & 0xFF000000) >> 24) / 255.0; + + cairo_set_source_rgba(cairoWindow, r, g, b, a); +} + +static void +pluginDrawSolid(InstanceData* instanceData, GdkDrawable* gdkWindow, + int x, int y, int width, int height) +{ + cairo_t* cairoWindow = gdk_cairo_create(gdkWindow); + + if (!instanceData->hasWidget) { + NPRect* clip = &instanceData->window.clipRect; + cairo_rectangle(cairoWindow, clip->left, clip->top, + clip->right - clip->left, clip->bottom - clip->top); + cairo_clip(cairoWindow); + } + + GdkRectangle windowRect = { x, y, width, height }; + gdk_cairo_rectangle(cairoWindow, &windowRect); + SetCairoRGBA(cairoWindow, 0xFF000000); + + cairo_fill(cairoWindow); + cairo_destroy(cairoWindow); +} + +static void +pluginDrawWindow(InstanceData* instanceData, GdkDrawable* gdkWindow) +{ + NPWindow& window = instanceData->window; + // When we have a widget, window.x/y are meaningless since our + // widget is always positioned correctly and we just draw into it at 0,0 + int x = instanceData->hasWidget ? 0 : window.x; + int y = instanceData->hasWidget ? 0 : window.y; + int width = window.width; + int height = window.height; + + NPP npp = instanceData->npp; + if (!npp) + return; + + const char* uaString = NPN_UserAgent(npp); + if (!uaString) + return; + + GdkGC* gdkContext = gdk_gc_new(gdkWindow); + if (!gdkContext) + return; + + if (!instanceData->hasWidget) { + NPRect* clip = &window.clipRect; + GdkRectangle gdkClip = { clip->left, clip->top, clip->right - clip->left, + clip->bottom - clip->top }; + gdk_gc_set_clip_rectangle(gdkContext, &gdkClip); + } + + // draw a grey background for the plugin frame + GdkColor grey; + grey.red = grey.blue = grey.green = 32767; + gdk_gc_set_rgb_fg_color(gdkContext, &grey); + gdk_draw_rectangle(gdkWindow, gdkContext, TRUE, x, y, width, height); + + // draw a 3-pixel-thick black frame around the plugin + GdkColor black; + black.red = black.green = black.blue = 0; + gdk_gc_set_rgb_fg_color(gdkContext, &black); + gdk_gc_set_line_attributes(gdkContext, 3, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_MITER); + gdk_draw_rectangle(gdkWindow, gdkContext, FALSE, x + 1, y + 1, + width - 3, height - 3); + + // paint the UA string + PangoContext* pangoContext = gdk_pango_context_get(); + PangoLayout* pangoTextLayout = pango_layout_new(pangoContext); + pango_layout_set_width(pangoTextLayout, (width - 10) * PANGO_SCALE); + pango_layout_set_text(pangoTextLayout, uaString, -1); + gdk_draw_layout(gdkWindow, gdkContext, x + 5, y + 5, pangoTextLayout); + g_object_unref(pangoTextLayout); + + g_object_unref(gdkContext); +} + +static gboolean +ExposeWidget(GtkWidget* widget, GdkEventExpose* event, + gpointer user_data) +{ + InstanceData* instanceData = static_cast(user_data); + pluginDrawWindow(instanceData, event->window); + return TRUE; +} + +static gboolean +DeleteWidget(GtkWidget* widget, GdkEvent* event, gpointer user_data) +{ + InstanceData* instanceData = static_cast(user_data); + // Some plugins do not expect the plug to be removed from the socket before + // the plugin instance is destroyed. e.g. bug 485125 + if (instanceData->platformData->plug) + g_error("plug removed"); // this aborts + + return FALSE; +} + +void +pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) +{ + instanceData->window = *newWindow; + + NPSetWindowCallbackStruct *ws_info = + static_cast(newWindow->ws_info); + instanceData->platformData->display = ws_info->display; +} + +void +pluginWidgetInit(InstanceData* instanceData, void* oldWindow) +{ +#ifdef MOZ_X11 + GtkWidget* oldPlug = instanceData->platformData->plug; + if (oldPlug) { + instanceData->platformData->plug = 0; + gtk_widget_destroy(oldPlug); + } + + GdkNativeWindow nativeWinId = + reinterpret_cast(instanceData->window.window); + + /* create a GtkPlug container */ + GtkWidget* plug = gtk_plug_new(nativeWinId); + + /* make sure the widget is capable of receiving focus */ + GTK_WIDGET_SET_FLAGS (GTK_WIDGET(plug), GTK_CAN_FOCUS); + + /* all the events that our widget wants to receive */ + gtk_widget_add_events(plug, GDK_EXPOSURE_MASK); + g_signal_connect(G_OBJECT(plug), "expose-event", G_CALLBACK(ExposeWidget), + instanceData); + g_signal_connect(G_OBJECT(plug), "delete-event", G_CALLBACK(DeleteWidget), + instanceData); + gtk_widget_show(plug); + + instanceData->platformData->plug = plug; +#endif +} + +int16_t +pluginHandleEvent(InstanceData* instanceData, void* event) +{ +#ifdef MOZ_X11 + XEvent *nsEvent = (XEvent *)event; + + if (nsEvent->type != GraphicsExpose) + return 0; + + XGraphicsExposeEvent *expose = &nsEvent->xgraphicsexpose; + instanceData->window.window = (void*)(expose->drawable); + + GdkNativeWindow nativeWinId = + reinterpret_cast(instanceData->window.window); + GdkDrawable* gdkWindow = GDK_DRAWABLE(gdk_window_foreign_new(nativeWinId)); + pluginDrawWindow(instanceData, gdkWindow); + g_object_unref(gdkWindow); +#endif + return 0; +} + +int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge) +{ + if (!instanceData->hasWidget) + return NPTEST_INT32_ERROR; + GtkWidget* plug = instanceData->platformData->plug; + if (!plug) + return NPTEST_INT32_ERROR; + GdkWindow* plugWnd = plug->window; + if (!plugWnd) + return NPTEST_INT32_ERROR; + + GdkWindow* toplevelGdk = 0; +#ifdef MOZ_X11 + Window toplevel = 0; + NPN_GetValue(instanceData->npp, NPNVnetscapeWindow, &toplevel); + if (!toplevel) + return NPTEST_INT32_ERROR; + toplevelGdk = gdk_window_foreign_new(toplevel); +#endif + if (!toplevelGdk) + return NPTEST_INT32_ERROR; + + GdkRectangle toplevelFrameExtents; + gdk_window_get_frame_extents(toplevelGdk, &toplevelFrameExtents); + g_object_unref(toplevelGdk); + + gint pluginWidth, pluginHeight; + gdk_drawable_get_size(GDK_DRAWABLE(plugWnd), &pluginWidth, &pluginHeight); + gint pluginOriginX, pluginOriginY; + gdk_window_get_origin(plugWnd, &pluginOriginX, &pluginOriginY); + gint pluginX = pluginOriginX - toplevelFrameExtents.x; + gint pluginY = pluginOriginY - toplevelFrameExtents.y; + + switch (edge) { + case EDGE_LEFT: + return pluginX; + case EDGE_TOP: + return pluginY; + case EDGE_RIGHT: + return pluginX + pluginWidth; + case EDGE_BOTTOM: + return pluginY + pluginHeight; + } + + return NPTEST_INT32_ERROR; +} + +#ifdef MOZ_X11 +static void intersectWithShapeRects(Display* display, Window window, + int kind, GdkRegion* region) +{ + int count = -1, order; + XRectangle* shapeRects = + XShapeGetRectangles(display, window, kind, &count, &order); + // The documentation says that shapeRects will be NULL when the + // extension is not supported. Unfortunately XShapeGetRectangles + // also returns NULL when the region is empty, so we can't treat + // NULL as failure. I hope this way is OK. + if (count < 0) + return; + + GdkRegion* shapeRegion = gdk_region_new(); + if (!shapeRegion) { + XFree(shapeRects); + return; + } + + for (int i = 0; i < count; ++i) { + XRectangle* r = &shapeRects[i]; + GdkRectangle rect = { r->x, r->y, r->width, r->height }; + gdk_region_union_with_rect(shapeRegion, &rect); + } + XFree(shapeRects); + + gdk_region_intersect(region, shapeRegion); + gdk_region_destroy(shapeRegion); +} +#endif + +static GdkRegion* computeClipRegion(InstanceData* instanceData) +{ + if (!instanceData->hasWidget) + return 0; + + GtkWidget* plug = instanceData->platformData->plug; + if (!plug) + return 0; + GdkWindow* plugWnd = plug->window; + if (!plugWnd) + return 0; + + gint plugWidth, plugHeight; + gdk_drawable_get_size(GDK_DRAWABLE(plugWnd), &plugWidth, &plugHeight); + GdkRectangle pluginRect = { 0, 0, plugWidth, plugHeight }; + GdkRegion* region = gdk_region_rectangle(&pluginRect); + if (!region) + return 0; + + int pluginX = 0, pluginY = 0; + +#ifdef MOZ_X11 + Display* display = GDK_WINDOW_XDISPLAY(plugWnd); + Window window = GDK_WINDOW_XWINDOW(plugWnd); + + Window toplevel = 0; + NPN_GetValue(instanceData->npp, NPNVnetscapeWindow, &toplevel); + if (!toplevel) + return 0; + + for (;;) { + Window root; + int x, y; + unsigned int width, height, border_width, depth; + if (!XGetGeometry(display, window, &root, &x, &y, &width, &height, + &border_width, &depth)) { + gdk_region_destroy(region); + return 0; + } + + GdkRectangle windowRect = { 0, 0, width, height }; + GdkRegion* windowRgn = gdk_region_rectangle(&windowRect); + if (!windowRgn) { + gdk_region_destroy(region); + return 0; + } + intersectWithShapeRects(display, window, ShapeBounding, windowRgn); + intersectWithShapeRects(display, window, ShapeClip, windowRgn); + gdk_region_offset(windowRgn, -pluginX, -pluginY); + gdk_region_intersect(region, windowRgn); + gdk_region_destroy(windowRgn); + + // Stop now if we've reached the toplevel. Stopping here means + // clipping performed by the toplevel window is taken into account. + if (window == toplevel) + break; + + Window parent; + Window* children; + unsigned int nchildren; + if (!XQueryTree(display, window, &root, &parent, &children, &nchildren)) { + gdk_region_destroy(region); + return 0; + } + XFree(children); + + pluginX += x; + pluginY += y; + + window = parent; + } +#endif + // pluginX and pluginY are now relative to the toplevel. Make them + // relative to the window frame top-left. + GdkWindow* toplevelGdk = gdk_window_foreign_new(window); + if (!toplevelGdk) + return 0; + GdkRectangle toplevelFrameExtents; + gdk_window_get_frame_extents(toplevelGdk, &toplevelFrameExtents); + gint toplevelOriginX, toplevelOriginY; + gdk_window_get_origin(toplevelGdk, &toplevelOriginX, &toplevelOriginY); + g_object_unref(toplevelGdk); + + pluginX += toplevelOriginX - toplevelFrameExtents.x; + pluginY += toplevelOriginY - toplevelFrameExtents.y; + + gdk_region_offset(region, pluginX, pluginY); + return region; +} + +int32_t pluginGetClipRegionRectCount(InstanceData* instanceData) +{ + GdkRegion* region = computeClipRegion(instanceData); + if (!region) + return NPTEST_INT32_ERROR; + + GdkRectangle* rects; + gint nrects; + gdk_region_get_rectangles(region, &rects, &nrects); + gdk_region_destroy(region); + g_free(rects); + return nrects; +} + +int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, + int32_t rectIndex, RectEdge edge) +{ + GdkRegion* region = computeClipRegion(instanceData); + if (!region) + return NPTEST_INT32_ERROR; + + GdkRectangle* rects; + gint nrects; + gdk_region_get_rectangles(region, &rects, &nrects); + gdk_region_destroy(region); + if (rectIndex >= nrects) { + g_free(rects); + return NPTEST_INT32_ERROR; + } + + GdkRectangle rect = rects[rectIndex]; + g_free(rects); + + switch (edge) { + case EDGE_LEFT: + return rect.x; + case EDGE_TOP: + return rect.y; + case EDGE_RIGHT: + return rect.x + rect.width; + case EDGE_BOTTOM: + return rect.y + rect.height; + } + return NPTEST_INT32_ERROR; +} diff --git a/dom/plugins/testplugin/npipctest_macosx.mm b/dom/plugins/testplugin/npipctest_macosx.mm new file mode 100644 index 000000000000..fc866cbc7791 --- /dev/null +++ b/dom/plugins/testplugin/npipctest_macosx.mm @@ -0,0 +1,290 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest_platform.h" +#include + +bool +pluginSupportsWindowMode() +{ + return false; +} + +bool +pluginSupportsWindowlessMode() +{ + return true; +} + +NPError +pluginInstanceInit(InstanceData* instanceData) +{ + NPP npp = instanceData->npp; + // select the right drawing model if necessary + NPBool supportsCoreGraphics = false; + if (NPN_GetValue(npp, NPNVsupportsCoreGraphicsBool, &supportsCoreGraphics) == NPERR_NO_ERROR && supportsCoreGraphics) { + NPN_SetValue(npp, NPPVpluginDrawingModel, (void*)NPDrawingModelCoreGraphics); + } else { + printf("CoreGraphics drawing model not supported, can't create a plugin instance.\n"); + return NPERR_INCOMPATIBLE_VERSION_ERROR; + } + return NPERR_NO_ERROR; +} + +void +pluginInstanceShutdown(InstanceData* instanceData) +{ +} + +static bool +RectEquals(const NPRect& r1, const NPRect& r2) +{ + return r1.left == r2.left && r1.top == r2.top && + r1.right == r2.right && r1.bottom == r2.bottom; +} + +void +pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) +{ + // Ugh. Due to a terrible Gecko bug, we have to ignore position changes + // when the clip rect doesn't change; the position can be wrong + // when set by a path other than nsObjectFrame::FixUpPluginWindow. + int32_t oldX = instanceData->window.x; + int32_t oldY = instanceData->window.y; + bool clipChanged = + !RectEquals(instanceData->window.clipRect, newWindow->clipRect); + instanceData->window = *newWindow; + if (!clipChanged) { + instanceData->window.x = oldX; + instanceData->window.y = oldY; + } +} + +void +pluginWidgetInit(InstanceData* instanceData, void* oldWindow) +{ + // Should never be called since we don't support window mode +} + +static void +GetColorsFromRGBA(PRUint32 rgba, float* r, float* g, float* b, float* a) +{ + *b = (rgba & 0xFF) / 255.0; + *g = ((rgba & 0xFF00) >> 8) / 255.0; + *r = ((rgba & 0xFF0000) >> 16) / 255.0; + *a = ((rgba & 0xFF000000) >> 24) / 255.0; +} + +static void +pluginDraw(InstanceData* instanceData) +{ + if (!instanceData) + return; + + NPP npp = instanceData->npp; + if (!npp) + return; + + const char* uaString = NPN_UserAgent(npp); + if (!uaString) + return; + + NPWindow window = instanceData->window; + CGContextRef cgContext = ((NP_CGContext*)(window.window))->context; + + float windowWidth = window.width; + float windowHeight = window.height; + + switch(instanceData->scriptableObject->drawMode) { + case DM_DEFAULT: { + CFStringRef uaCFString = CFStringCreateWithCString(kCFAllocatorDefault, uaString, kCFStringEncodingASCII); + // save the cgcontext gstate + CGContextSaveGState(cgContext); + + // we get a flipped context + CGContextTranslateCTM(cgContext, 0.0, windowHeight); + CGContextScaleCTM(cgContext, 1.0, -1.0); + + // draw a gray background for the plugin + CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); + CGContextSetGrayFillColor(cgContext, 0.5, 1.0); + CGContextDrawPath(cgContext, kCGPathFill); + + // draw a black frame around the plugin + CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); + CGContextSetGrayStrokeColor(cgContext, 0.0, 1.0); + CGContextSetLineWidth(cgContext, 6.0); + CGContextStrokePath(cgContext); + + // draw the UA string using ATSUI + CGContextSetGrayFillColor(cgContext, 0.0, 1.0); + ATSUStyle atsuStyle; + ATSUCreateStyle(&atsuStyle); + CFIndex stringLength = CFStringGetLength(uaCFString); + UniChar* unicharBuffer = (UniChar*)malloc((stringLength + 1) * sizeof(UniChar)); + CFStringGetCharacters(uaCFString, CFRangeMake(0, stringLength), unicharBuffer); + UniCharCount runLengths = kATSUToTextEnd; + ATSUTextLayout atsuLayout; + ATSUCreateTextLayoutWithTextPtr(unicharBuffer, + kATSUFromTextBeginning, + kATSUToTextEnd, + stringLength, + 1, + &runLengths, + &atsuStyle, + &atsuLayout); + ATSUAttributeTag contextTag = kATSUCGContextTag; + ByteCount byteSize = sizeof(CGContextRef); + ATSUAttributeValuePtr contextATSUPtr = &cgContext; + ATSUSetLayoutControls(atsuLayout, 1, &contextTag, &byteSize, &contextATSUPtr); + ATSUTextMeasurement lineAscent, lineDescent; + ATSUGetLineControl(atsuLayout, + kATSUFromTextBeginning, + kATSULineAscentTag, + sizeof(ATSUTextMeasurement), + &lineAscent, + &byteSize); + ATSUGetLineControl(atsuLayout, + kATSUFromTextBeginning, + kATSULineDescentTag, + sizeof(ATSUTextMeasurement), + &lineDescent, + &byteSize); + float lineHeight = FixedToFloat(lineAscent) + FixedToFloat(lineDescent); + ItemCount softBreakCount; + ATSUBatchBreakLines(atsuLayout, + kATSUFromTextBeginning, + stringLength, + FloatToFixed(windowWidth - 10.0), + &softBreakCount); + ATSUGetSoftLineBreaks(atsuLayout, + kATSUFromTextBeginning, + kATSUToTextEnd, + 0, NULL, &softBreakCount); + UniCharArrayOffset* softBreaks = (UniCharArrayOffset*)malloc(softBreakCount * sizeof(UniCharArrayOffset)); + ATSUGetSoftLineBreaks(atsuLayout, + kATSUFromTextBeginning, + kATSUToTextEnd, + softBreakCount, softBreaks, &softBreakCount); + UniCharArrayOffset currentDrawOffset = kATSUFromTextBeginning; + unsigned int i = 0; + while (i < softBreakCount) { + ATSUDrawText(atsuLayout, currentDrawOffset, softBreaks[i], FloatToFixed(5.0), FloatToFixed(windowHeight - 5.0 - (lineHeight * (i + 1.0)))); + currentDrawOffset = softBreaks[i]; + i++; + } + ATSUDrawText(atsuLayout, currentDrawOffset, kATSUToTextEnd, FloatToFixed(5.0), FloatToFixed(windowHeight - 5.0 - (lineHeight * (i + 1.0)))); + free(unicharBuffer); + free(softBreaks); + + // restore the cgcontext gstate + CGContextRestoreGState(cgContext); + } + case DM_SOLID_COLOR: { + // save the cgcontext gstate + CGContextSaveGState(cgContext); + + // we get a flipped context + CGContextTranslateCTM(cgContext, 0.0, windowHeight); + CGContextScaleCTM(cgContext, 1.0, -1.0); + + // draw a solid background for the plugin + CGContextAddRect(cgContext, CGRectMake(0, 0, windowWidth, windowHeight)); + + float r,g,b,a; + GetColorsFromRGBA(instanceData->scriptableObject->drawColor, &r, &g, &b, &a); + CGContextSetRGBFillColor(cgContext, r, g, b, a); + CGContextDrawPath(cgContext, kCGPathFill); + + // restore the cgcontext gstate + CGContextRestoreGState(cgContext); + break; + } + } +} + +int16_t +pluginHandleEvent(InstanceData* instanceData, void* event) +{ + EventRecord* carbonEvent = (EventRecord*)event; + if (carbonEvent && (carbonEvent->what == updateEvt)) { + pluginDraw(instanceData); + return 1; + } + return 0; +} + +int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge) +{ + NPWindow* w = &instanceData->window; + switch (edge) { + case EDGE_LEFT: + return w->x; + case EDGE_TOP: + return w->y; + case EDGE_RIGHT: + return w->x + w->width; + case EDGE_BOTTOM: + return w->y + w->height; + } + return NPTEST_INT32_ERROR; +} + +int32_t pluginGetClipRegionRectCount(InstanceData* instanceData) +{ + return 1; +} + +int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, + int32_t rectIndex, RectEdge edge) +{ + if (rectIndex != 0) + return NPTEST_INT32_ERROR; + + // We have to add the Cocoa titlebar height here since the clip rect + // is being returned relative to that + static const int COCOA_TITLEBAR_HEIGHT = 22; + + NPWindow* w = &instanceData->window; + switch (edge) { + case EDGE_LEFT: + return w->clipRect.left; + case EDGE_TOP: + return w->clipRect.top + COCOA_TITLEBAR_HEIGHT; + case EDGE_RIGHT: + return w->clipRect.right; + case EDGE_BOTTOM: + return w->clipRect.bottom + COCOA_TITLEBAR_HEIGHT; + } + return NPTEST_INT32_ERROR; +} diff --git a/dom/plugins/testplugin/npipctest_os2.cpp b/dom/plugins/testplugin/npipctest_os2.cpp new file mode 100644 index 000000000000..402423dea661 --- /dev/null +++ b/dom/plugins/testplugin/npipctest_os2.cpp @@ -0,0 +1,93 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest_platform.h" + +bool +pluginSupportsWindowMode() +{ + return false; +} + +bool +pluginSupportsWindowlessMode() +{ + return true; +} + +NPError +pluginInstanceInit(InstanceData* instanceData) +{ + return NPERR_NO_ERROR; +} + +void +pluginInstanceShutdown(InstanceData* instanceData) +{ +} + +void +pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) +{ + instanceData->window = *newWindow; +} + +void +pluginWidgetInit(InstanceData* instanceData, void* oldWindow) +{ +} + +int16_t +pluginHandleEvent(InstanceData* instanceData, void* event) +{ + return 0; +} + +int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge) +{ + // XXX nothing here yet since we don't support windowed plugins + return NPTEST_INT32_ERROR; +} + +int32_t pluginGetClipRegionRectCount(InstanceData* instanceData) +{ + // XXX nothing here yet since we don't support windowed plugins + return NPTEST_INT32_ERROR; +} + +int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, + int32_t rectIndex, RectEdge edge) +{ + // XXX nothing here yet since we don't support windowed plugins + return NPTEST_INT32_ERROR; +} diff --git a/dom/plugins/testplugin/npipctest_platform.h b/dom/plugins/testplugin/npipctest_platform.h new file mode 100644 index 000000000000..880ce926f1e7 --- /dev/null +++ b/dom/plugins/testplugin/npipctest_platform.h @@ -0,0 +1,116 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nptest_platform_h_ +#define nptest_platform_h_ + +#include "npipctest.h" + +/** + * Returns true if the plugin supports windowed mode + */ +bool pluginSupportsWindowMode(); + +/** + * Returns true if the plugin supports windowless mode. At least one of + * "pluginSupportsWindowMode" and "pluginSupportsWindowlessMode" must + * return true. + */ +bool pluginSupportsWindowlessMode(); + +/** + * Initialize the plugin instance. Returning an error here will cause the + * plugin instantiation to fail. + */ +NPError pluginInstanceInit(InstanceData* instanceData); + +/** + * Shutdown the plugin instance. + */ +void pluginInstanceShutdown(InstanceData* instanceData); + +/** + * Set the instanceData's window to newWindow. + */ +void pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow); + +/** + * Initialize the window for a windowed plugin. oldWindow is the old + * native window value. This will never be called for windowless plugins. + */ +void pluginWidgetInit(InstanceData* instanceData, void* oldWindow); + +/** + * Handle an event for a windowless plugin. (Windowed plugins are + * responsible for listening for their own events.) + */ +int16_t pluginHandleEvent(InstanceData* instanceData, void* event); + +enum RectEdge { + EDGE_LEFT = 0, + EDGE_TOP = 1, + EDGE_RIGHT = 2, + EDGE_BOTTOM = 3 +}; + +enum { + NPTEST_INT32_ERROR = 0x7FFFFFFF +}; + +/** + * Return the coordinate of the given edge of the plugin's area, relative + * to the top-left corner of the toplevel window containing the plugin, + * including window decorations. Only works for window-mode plugins + * and Mac plugins. + * Returns NPTEST_ERROR on error. + */ +int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge); + +/** + * Return the number of rectangles in the plugin's clip region. Only + * works for window-mode plugins and Mac plugins. + * Returns NPTEST_ERROR on error. + */ +int32_t pluginGetClipRegionRectCount(InstanceData* instanceData); + +/** + * Return the coordinate of the given edge of a rectangle in the plugin's + * clip region, relative to the top-left corner of the toplevel window + * containing the plugin, including window decorations. Only works for + * window-mode plugins and Mac plugins. + * Returns NPTEST_ERROR on error. + */ +int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, + int32_t rectIndex, RectEdge edge); + +#endif // nptest_platform_h_ diff --git a/dom/plugins/testplugin/npipctest_qt.cpp b/dom/plugins/testplugin/npipctest_qt.cpp new file mode 100644 index 000000000000..402423dea661 --- /dev/null +++ b/dom/plugins/testplugin/npipctest_qt.cpp @@ -0,0 +1,93 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest_platform.h" + +bool +pluginSupportsWindowMode() +{ + return false; +} + +bool +pluginSupportsWindowlessMode() +{ + return true; +} + +NPError +pluginInstanceInit(InstanceData* instanceData) +{ + return NPERR_NO_ERROR; +} + +void +pluginInstanceShutdown(InstanceData* instanceData) +{ +} + +void +pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) +{ + instanceData->window = *newWindow; +} + +void +pluginWidgetInit(InstanceData* instanceData, void* oldWindow) +{ +} + +int16_t +pluginHandleEvent(InstanceData* instanceData, void* event) +{ + return 0; +} + +int32_t pluginGetEdge(InstanceData* instanceData, RectEdge edge) +{ + // XXX nothing here yet since we don't support windowed plugins + return NPTEST_INT32_ERROR; +} + +int32_t pluginGetClipRegionRectCount(InstanceData* instanceData) +{ + // XXX nothing here yet since we don't support windowed plugins + return NPTEST_INT32_ERROR; +} + +int32_t pluginGetClipRegionRectEdge(InstanceData* instanceData, + int32_t rectIndex, RectEdge edge) +{ + // XXX nothing here yet since we don't support windowed plugins + return NPTEST_INT32_ERROR; +} diff --git a/dom/plugins/testplugin/npipctest_utils.cpp b/dom/plugins/testplugin/npipctest_utils.cpp new file mode 100644 index 000000000000..a476f2e4aaf2 --- /dev/null +++ b/dom/plugins/testplugin/npipctest_utils.cpp @@ -0,0 +1,119 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest_utils.h" + +#include +#include +#include + +NPUTF8* +createCStringFromNPVariant(const NPVariant* variant) +{ + size_t length = NPVARIANT_TO_STRING(*variant).UTF8Length; + NPUTF8* result = (NPUTF8*)malloc(length + 1); + memcpy(result, NPVARIANT_TO_STRING(*variant).UTF8Characters, length); + result[length] = '\0'; + return result; +} + +NPIdentifier +variantToIdentifier(NPVariant variant) +{ + if (NPVARIANT_IS_STRING(variant)) + return stringVariantToIdentifier(variant); + else if (NPVARIANT_IS_INT32(variant)) + return int32VariantToIdentifier(variant); + else if (NPVARIANT_IS_DOUBLE(variant)) + return doubleVariantToIdentifier(variant); + return 0; +} + +NPIdentifier +stringVariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_STRING(variant)); + NPUTF8* utf8String = createCStringFromNPVariant(&variant); + NPIdentifier identifier = NPN_GetStringIdentifier(utf8String); + free(utf8String); + return identifier; +} + +NPIdentifier +int32VariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_INT32(variant)); + int32_t integer = NPVARIANT_TO_INT32(variant); + return NPN_GetIntIdentifier(integer); +} + +NPIdentifier +doubleVariantToIdentifier(NPVariant variant) +{ + assert(NPVARIANT_IS_DOUBLE(variant)); + double value = NPVARIANT_TO_DOUBLE(variant); + // sadly there is no "getdoubleidentifier" + int32_t integer = static_cast(value); + return NPN_GetIntIdentifier(integer); +} + +/* + * Parse a color in hex format, like AARRGGBB + * If the string is short, portions to the left are assumed omitted. + * R G B default to 0, A defaults to 0xFF + */ +PRUint32 +parseHexColor(char* color) +{ + int len = strlen(color); + PRUint8 bgra[4] = { 0, 0, 0, 0xFF }; + int i = 0; + + // start from the right and work to the left + while (len > 0) { + char byte[3]; + if (len > 1) { + // parse two hex digits + byte[0] = color[len - 2]; + byte[1] = color[len - 1]; + } + else { + // only one digit left + byte[0] = '0'; + byte[1] = color[len - 1]; + } + byte[2] = '\0'; + + bgra[i] = (PRUint8)(strtoul(byte, NULL, 16) & 0xFF); + i++; + len -= 2; + } + return (bgra[3] << 24) | (bgra[2] << 16) | (bgra[1] << 8) | bgra[0]; +} diff --git a/dom/plugins/testplugin/npipctest_utils.h b/dom/plugins/testplugin/npipctest_utils.h new file mode 100644 index 000000000000..374351b1d8fd --- /dev/null +++ b/dom/plugins/testplugin/npipctest_utils.h @@ -0,0 +1,45 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nptest_utils_h_ +#define nptest_utils_h_ + +#include "npipctest.h" + +NPUTF8* createCStringFromNPVariant(const NPVariant* variant); + +NPIdentifier variantToIdentifier(NPVariant variant); +NPIdentifier stringVariantToIdentifier(NPVariant variant); +NPIdentifier int32VariantToIdentifier(NPVariant variant); +NPIdentifier doubleVariantToIdentifier(NPVariant variant); + +PRUint32 parseHexColor(char* color); + +#endif // nptest_utils_h_ diff --git a/dom/plugins/testplugin/npipctest_windows.cpp b/dom/plugins/testplugin/npipctest_windows.cpp new file mode 100644 index 000000000000..fd7b1577c073 --- /dev/null +++ b/dom/plugins/testplugin/npipctest_windows.cpp @@ -0,0 +1,406 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * + * Copyright (c) 2008, Mozilla Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the Mozilla Corporation nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributor(s): + * Josh Aas + * Jim Mathies + * + * ***** END LICENSE BLOCK ***** */ + +#include "npipctest_platform.h" + +#include + +#pragma comment(lib, "msimg32.lib") + +void SetSubclass(HWND hWnd, InstanceData* instanceData); +void ClearSubclass(HWND hWnd); +LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +bool +pluginSupportsWindowMode() +{ + return true; +} + +bool +pluginSupportsWindowlessMode() +{ + return true; +} + +NPError +pluginInstanceInit(InstanceData* instanceData) +{ + return NPERR_NO_ERROR; +} + +void +pluginInstanceShutdown(InstanceData* instanceData) +{ +} + +void +pluginDoSetWindow(InstanceData* instanceData, NPWindow* newWindow) +{ + instanceData->window = *newWindow; +} + +void +pluginWidgetInit(InstanceData* instanceData, void* oldWindow) +{ + HWND hWnd = (HWND)instanceData->window.window; + if (oldWindow) { + HWND hWndOld = (HWND)oldWindow; + ClearSubclass(hWndOld); + } + SetSubclass(hWnd, instanceData); +} + +static void +drawToDC(InstanceData* instanceData, HDC dc, + int x, int y, int width, int height) +{ + HBITMAP offscreenBitmap = ::CreateCompatibleBitmap(dc, width, height); + if (!offscreenBitmap) + return; + HDC offscreenDC = ::CreateCompatibleDC(dc); + if (!offscreenDC) { + ::DeleteObject(offscreenBitmap); + return; + } + + HBITMAP oldOffscreenBitmap = + (HBITMAP)::SelectObject(offscreenDC, offscreenBitmap); + ::SetBkMode(offscreenDC, TRANSPARENT); + BYTE alpha = 255; + RECT fill = { 0, 0, width, height }; + + HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0)); + if (brush) { + ::FillRect(offscreenDC, &fill, brush); + ::DeleteObject(brush); + } + if (width > 6 && height > 6) { + brush = ::CreateSolidBrush(RGB(192, 192, 192)); + if (brush) { + RECT inset = { 3, 3, width - 3, height - 3 }; + ::FillRect(offscreenDC, &inset, brush); + ::DeleteObject(brush); + } + } + + const char* uaString = NPN_UserAgent(instanceData->npp); + if (uaString && width > 10 && height > 10) { + HFONT font = + ::CreateFontA(20, 0, 0, 0, 400, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, 5, // CLEARTYPE_QUALITY + DEFAULT_PITCH, "Arial"); + if (font) { + HFONT oldFont = (HFONT)::SelectObject(offscreenDC, font); + RECT inset = { 5, 5, width - 5, height - 5 }; + ::DrawTextA(offscreenDC, uaString, -1, &inset, + DT_LEFT | DT_TOP | DT_NOPREFIX | DT_WORDBREAK); + ::SelectObject(offscreenDC, oldFont); + ::DeleteObject(font); + } + } + + BLENDFUNCTION blendFunc; + blendFunc.BlendOp = AC_SRC_OVER; + blendFunc.BlendFlags = 0; + blendFunc.SourceConstantAlpha = alpha; + blendFunc.AlphaFormat = 0; + ::AlphaBlend(dc, x, y, width, height, offscreenDC, 0, 0, width, height, + blendFunc); + ::SelectObject(offscreenDC, oldOffscreenBitmap); + ::DeleteObject(offscreenDC); + ::DeleteObject(offscreenBitmap); +} + +void +pluginDraw(InstanceData* instanceData) +{ + NPP npp = instanceData->npp; + if (!npp) + return; + + HDC hdc = NULL; + PAINTSTRUCT ps; + + if (instanceData->hasWidget) + hdc = ::BeginPaint((HWND)instanceData->window.window, &ps); + else + hdc = (HDC)instanceData->window.window; + + if (hdc == NULL) + return; + + // Push the browser's hdc on the resource stack. If this test plugin is windowless, + // we share the drawing surface with the rest of the browser. + int savedDCID = SaveDC(hdc); + + // When we have a widget, window.x/y are meaningless since our widget + // is always positioned correctly and we just draw into it at 0,0. + int x = instanceData->hasWidget ? 0 : instanceData->window.x; + int y = instanceData->hasWidget ? 0 : instanceData->window.y; + int width = instanceData->window.width; + int height = instanceData->window.height; + drawToDC(instanceData, hdc, x, y, width, height); + + // Pop our hdc changes off the resource stack + RestoreDC(hdc, savedDCID); + + if (instanceData->hasWidget) + ::EndPaint((HWND)instanceData->window.window, &ps); +} + +/* script interface */ + +int32_t +pluginGetEdge(InstanceData* instanceData, RectEdge edge) +{ + if (!instanceData || !instanceData->hasWidget) + return NPTEST_INT32_ERROR; + + // Get the plugin client rect in screen coordinates + RECT rect = {0}; + if (!::GetClientRect((HWND)instanceData->window.window, &rect)) + return NPTEST_INT32_ERROR; + ::MapWindowPoints((HWND)instanceData->window.window, NULL, (LPPOINT)&rect, 2); + + // Get the toplevel window frame rect in screen coordinates + HWND rootWnd = ::GetAncestor((HWND)instanceData->window.window, GA_ROOT); + if (!rootWnd) + return NPTEST_INT32_ERROR; + RECT rootRect; + if (!::GetWindowRect(rootWnd, &rootRect)) + return NPTEST_INT32_ERROR; + + switch (edge) { + case EDGE_LEFT: + return rect.left - rootRect.left; + case EDGE_TOP: + return rect.top - rootRect.top; + case EDGE_RIGHT: + return rect.right - rootRect.left; + case EDGE_BOTTOM: + return rect.bottom - rootRect.top; + } + + return NPTEST_INT32_ERROR; +} + +static BOOL +getWindowRegion(HWND wnd, HRGN rgn) +{ + if (::GetWindowRgn(wnd, rgn) != ERROR) + return TRUE; + + RECT clientRect; + if (!::GetClientRect(wnd, &clientRect)) + return FALSE; + return ::SetRectRgn(rgn, 0, 0, clientRect.right, clientRect.bottom); +} + +static RGNDATA* +computeClipRegion(InstanceData* instanceData) +{ + HWND wnd = (HWND)instanceData->window.window; + HRGN rgn = ::CreateRectRgn(0, 0, 0, 0); + if (!rgn) + return NULL; + HRGN ancestorRgn = ::CreateRectRgn(0, 0, 0, 0); + if (!ancestorRgn) { + ::DeleteObject(rgn); + return NULL; + } + if (!getWindowRegion(wnd, rgn)) { + ::DeleteObject(ancestorRgn); + ::DeleteObject(rgn); + return NULL; + } + + HWND ancestor = wnd; + for (;;) { + ancestor = ::GetAncestor(ancestor, GA_PARENT); + if (!ancestor || ancestor == ::GetDesktopWindow()) { + ::DeleteObject(ancestorRgn); + + DWORD size = ::GetRegionData(rgn, 0, NULL); + if (!size) { + ::DeleteObject(rgn); + return NULL; + } + + HANDLE heap = ::GetProcessHeap(); + RGNDATA* data = static_cast(::HeapAlloc(heap, 0, size)); + if (!data) { + ::DeleteObject(rgn); + return NULL; + } + DWORD result = ::GetRegionData(rgn, size, data); + ::DeleteObject(rgn); + if (!result) { + ::HeapFree(heap, 0, data); + return NULL; + } + + return data; + } + + if (!getWindowRegion(ancestor, ancestorRgn)) { + ::DeleteObject(ancestorRgn); + ::DeleteObject(rgn); + return 0; + } + + POINT pt = { 0, 0 }; + ::MapWindowPoints(ancestor, wnd, &pt, 1); + if (::OffsetRgn(ancestorRgn, pt.x, pt.y) == ERROR || + ::CombineRgn(rgn, rgn, ancestorRgn, RGN_AND) == ERROR) { + ::DeleteObject(ancestorRgn); + ::DeleteObject(rgn); + return 0; + } + } +} + +int32_t +pluginGetClipRegionRectCount(InstanceData* instanceData) +{ + RGNDATA* data = computeClipRegion(instanceData); + if (!data) + return NPTEST_INT32_ERROR; + + int32_t result = data->rdh.nCount; + ::HeapFree(::GetProcessHeap(), 0, data); + return result; +} + +static int32_t +addOffset(LONG coord, int32_t offset) +{ + if (offset == NPTEST_INT32_ERROR) + return NPTEST_INT32_ERROR; + return coord + offset; +} + +int32_t +pluginGetClipRegionRectEdge(InstanceData* instanceData, + int32_t rectIndex, RectEdge edge) +{ + RGNDATA* data = computeClipRegion(instanceData); + if (!data) + return NPTEST_INT32_ERROR; + + HANDLE heap = ::GetProcessHeap(); + if (rectIndex >= int32_t(data->rdh.nCount)) { + ::HeapFree(heap, 0, data); + return NPTEST_INT32_ERROR; + } + + RECT rect = reinterpret_cast(data->Buffer)[rectIndex]; + ::HeapFree(heap, 0, data); + + switch (edge) { + case EDGE_LEFT: + return addOffset(rect.left, pluginGetEdge(instanceData, EDGE_LEFT)); + case EDGE_TOP: + return addOffset(rect.top, pluginGetEdge(instanceData, EDGE_TOP)); + case EDGE_RIGHT: + return addOffset(rect.right, pluginGetEdge(instanceData, EDGE_LEFT)); + case EDGE_BOTTOM: + return addOffset(rect.bottom, pluginGetEdge(instanceData, EDGE_TOP)); + } + + return NPTEST_INT32_ERROR; +} + +/* windowless plugin events */ + +int16_t +pluginHandleEvent(InstanceData* instanceData, void* event) +{ + NPEvent * pe = (NPEvent*) event; + + if (pe == NULL || instanceData == NULL || + instanceData->window.type != NPWindowTypeDrawable) + return 0; + + switch((UINT)pe->event) { + case WM_PAINT: + pluginDraw(instanceData); + return 1; + } + + return 0; +} + +/* windowed plugin events */ + +LRESULT CALLBACK PluginWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC wndProc = (WNDPROC)GetProp(hWnd, "MozillaWndProc"); + if (!wndProc) + return 0; + InstanceData* pInstance = (InstanceData*)GetProp(hWnd, "InstanceData"); + if (!pInstance) + return 0; + + if (uMsg == WM_PAINT) { + pluginDraw(pInstance); + return 0; + } + + if (uMsg == WM_CLOSE) { + ClearSubclass((HWND)pInstance->window.window); + } + + return CallWindowProc(wndProc, hWnd, uMsg, wParam, lParam); +} + +void +ClearSubclass(HWND hWnd) +{ + if (GetProp(hWnd, "MozillaWndProc")) { + ::SetWindowLong(hWnd, GWL_WNDPROC, (long)GetProp(hWnd, "MozillaWndProc")); + RemoveProp(hWnd, "MozillaWndProc"); + RemoveProp(hWnd, "InstanceData"); + } +} + +void +SetSubclass(HWND hWnd, InstanceData* instanceData) +{ + // Subclass the plugin window so we can handle our own windows events. + SetProp(hWnd, "InstanceData", (HANDLE)instanceData); + WNDPROC origProc = (WNDPROC)::SetWindowLong(hWnd, GWL_WNDPROC, (long)PluginWndProc); + SetProp(hWnd, "MozillaWndProc", (HANDLE)origProc); +} diff --git a/ipc/glue/IPCMessageUtils.h b/ipc/glue/IPCMessageUtils.h index c68e61410faa..8387809c1e5c 100644 --- a/ipc/glue/IPCMessageUtils.h +++ b/ipc/glue/IPCMessageUtils.h @@ -154,23 +154,18 @@ struct ParamTraits > // Check to make sure the message is valid before requesting a huge chunk // of memory. - if (aMsg->IteratorHasRoomFor(*aIter, length * sizeof(E)) && - aResult->SetCapacity(length)) { - for (PRUint32 index = 0; index < length; index++) { - if (!ReadParam(aMsg, aIter, &aResult[index])) { - return false; - } - } + if (!aMsg->IteratorHasRoomFor(*aIter, length * sizeof(E))) { + return false; } - else { - // Push elements individually. - aResult->Clear(); - E element; - for (PRUint32 index = 0; index < length; index++) { - if (!ReadParam(aMsg, aIter, &element) || - !aResult->AppendElement(element)) { - return false; - } + + if (!aResult->SetLength(length)) { + return false; + } + + for (PRUint32 index = 0; index < length; index++) { + E& element = aResult->ElementAt(index); + if (!ReadParam(aMsg, aIter, &element)) { + return false; } }