From cc4f335fc9f60102b2e60368d721faab3e39609c Mon Sep 17 00:00:00 2001 From: Doug Turner Date: Mon, 26 Oct 2009 22:18:35 -0700 Subject: [PATCH] Bug 521257 - Support NPImageExpose on Maemo/Hildon only. r=roc --- layout/generic/nsObjectFrame.cpp | 197 +++++++++++++++++- modules/plugin/base/public/npapi.h | 22 ++ modules/plugin/base/src/nsNPAPIPlugin.cpp | 14 +- .../plugin/base/src/nsNPAPIPluginInstance.cpp | 15 ++ .../plugin/base/src/nsNPAPIPluginInstance.h | 3 + 5 files changed, 247 insertions(+), 4 deletions(-) diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 000d0e64c3b6..797129d508c9 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -139,6 +139,8 @@ #include "gfxWindowsSurface.h" #endif +#include "gfxImageSurface.h" + // accessibility support #ifdef ACCESSIBILITY #include "nsIAccessibilityService.h" @@ -169,7 +171,6 @@ enum { XKeyPress = KeyPress }; #endif #ifdef MOZ_PLATFORM_HILDON -#define MOZ_POST_VISIBILITY_EVENTS 1 #define MOZ_COMPOSITED_PLUGINS 1 #endif @@ -543,7 +544,19 @@ private: const nsIntRect& mDirtyRect; }; #endif +#ifdef MOZ_PLATFORM_HILDON + // On hildon, we attempt to use NPImageExpose which allows us faster + // painting. We hold a memory buffer to avoid reallocations on + // every plugin invalidate. + unsigned char* mImageExposeBuffer; + gfxIntSize mImageExposeBufferSize; + + nsresult NativeImageDraw(gfxContext *aContext, + NPWindow* mWindow, + const nsIntSize& mPluginSize, + const nsIntRect& mDirtyRect); +#endif }; // Mac specific code to fix up port position and clip @@ -2383,6 +2396,10 @@ nsPluginInstanceOwner::nsPluginInstanceOwner() mLastPoint = nsIntPoint(0,0); #endif +#ifdef MOZ_PLATFORM_HILDON + mImageExposeBuffer = nsnull; + mImageExposeBufferSize = gfxIntSize(0,0); +#endif PR_LOG(nsObjectFrameLM, PR_LOG_DEBUG, ("nsPluginInstanceOwner %p created\n", this)); } @@ -2436,6 +2453,13 @@ nsPluginInstanceOwner::~nsPluginInstanceOwner() if (mInstance) { mInstance->InvalidateOwner(); } + +#ifdef MOZ_PLATFORM_HILDON + if (mImageExposeBuffer) + free(mImageExposeBuffer); + mImageExposeBuffer = nsnull; +#endif + } /* @@ -3228,7 +3252,7 @@ nsresult nsPluginInstanceOwner::EnsureCachedAttrParamArrays() mNumCachedAttrs++; } - // "plugins.force.wmode" preference is forcing wmode type for plguins + // "plugins.force.wmode" preference is forcing wmode type for plugins // possible values - "opaque", "transparent", "windowed" nsAdoptingCString wmodeType = nsContentUtils::GetCharPref("plugins.force.wmode"); if (!wmodeType.IsEmpty()) @@ -4762,7 +4786,6 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, NPWindow* window; GetWindow(window); - Renderer renderer(window, mInstance, pluginSize, pluginDirtyRect); PRUint32 rendererFlags = Renderer::DRAW_SUPPORTS_OFFSET | Renderer::DRAW_SUPPORTS_CLIP_RECT | @@ -4778,6 +4801,16 @@ void nsPluginInstanceOwner::Paint(gfxContext* aContext, gfxContextAutoSaveRestore autoSR(aContext); aContext->Translate(pluginRect.pos); +#ifdef MOZ_PLATFORM_HILDON + PRBool simpleImageRender = PR_FALSE; + mInstance->GetValueFromPlugin(NPPVpluginWindowlessLocalBool, (void *)&simpleImageRender); + + if (simpleImageRender && NS_SUCCEEDED(NativeImageDraw(aContext, window, pluginSize, pluginDirtyRect))) + return; + +#endif + + Renderer renderer(window, mInstance, pluginSize, pluginDirtyRect); renderer.Draw(aContext, window->width, window->height, rendererFlags, nsnull); } @@ -4799,6 +4832,164 @@ DepthOfVisual(const Screen* screen, const Visual* visual) } #endif +#ifdef MOZ_PLATFORM_HILDON + +// NativeImageDraw +// +// This method supports the NPImageExpose API which is specific to the +// HILDON platform. Basically what it allows us to do is to pass a +// memory buffer into a plugin (namely flash), and have flase draw +// directly into the buffer. +// +// It may be faster if the rest of the system used offscreen image +// surfaces, but right now offscreen surfaces are using X +// surfaces. And because of this, we need to create a new image +// surface and copy that to the passed gfx context. +// +// This is not ideal and it should not be faster than what a +// windowless plugin can do. However, in A/B testing of flash on the +// N900, this approach is considerably faster. +// +// Hopefully this API can die off in favor of a more robust plugin API. + +nsresult +nsPluginInstanceOwner::NativeImageDraw(gfxContext *aContext, + NPWindow* mWindow, + const nsIntSize& mPluginSize, + const nsIntRect& mDirtyRect) +{ + PRBool doupdatewindow = PR_FALSE; + + if (mWindow->x || mWindow->y) { + mWindow->x = 0; + mWindow->y = 0; + doupdatewindow = PR_TRUE; + } + + if (nsIntSize(mWindow->width, mWindow->height) != mPluginSize) { + mWindow->width = mPluginSize.width; + mWindow->height = mPluginSize.height; + doupdatewindow = PR_TRUE; + } + + // The clip rect is relative to drawable top-left. + nsIntRect clipRect; + clipRect.x = 0; + clipRect.y = 0; + clipRect.width = mWindow->width; + clipRect.height = mWindow->height; + + NPRect newClipRect; + newClipRect.left = clipRect.x; + newClipRect.top = clipRect.y; + newClipRect.right = clipRect.XMost(); + newClipRect.bottom = clipRect.YMost(); + if (mWindow->clipRect.left != newClipRect.left || + mWindow->clipRect.top != newClipRect.top || + mWindow->clipRect.right != newClipRect.right || + mWindow->clipRect.bottom != newClipRect.bottom) { + mWindow->clipRect = newClipRect; + doupdatewindow = PR_TRUE; + } + + NPSetWindowCallbackStruct* ws_info = + static_cast(mWindow->ws_info); + ws_info->visual = 0; + ws_info->colormap = 0; + if (ws_info->depth != 24) { + ws_info->depth = 24; + doupdatewindow = PR_TRUE; + } + + if (doupdatewindow) + mInstance->SetWindow(mWindow); + + nsIntRect dirtyRect = mDirtyRect; + + // Intersect the dirty rect with the clip rect to ensure that it lies within + // the drawable. + if (!dirtyRect.IntersectRect(mDirtyRect, clipRect)) + return NS_ERROR_FAILURE; + + XEvent pluginEvent; + NPImageExpose imageExpose; + XGraphicsExposeEvent& exposeEvent = pluginEvent.xgraphicsexpose; + + // set the drawing info + exposeEvent.type = GraphicsExpose; + exposeEvent.display = 0; + + // Store imageExpose structure pointer as drawable member + exposeEvent.drawable = (Drawable)&imageExpose; + exposeEvent.x = mDirtyRect.x; + exposeEvent.y = mDirtyRect.y; + exposeEvent.width = mDirtyRect.width; + exposeEvent.height = mDirtyRect.height; + exposeEvent.count = 0; + + // information not set: + exposeEvent.serial = 0; + exposeEvent.send_event = False; + exposeEvent.major_code = 0; + exposeEvent.minor_code = 0; + + // defaults for NPImageExpose + imageExpose.depth = 24; + imageExpose.translateX = 1; + imageExpose.translateY = 1; + imageExpose.scaleX = 1; + imageExpose.scaleY = 1; + + // only have the plugin draw what is dirty + imageExpose.x = mDirtyRect.x; + imageExpose.y = mDirtyRect.y; + imageExpose.width = mDirtyRect.width; + imageExpose.height = mDirtyRect.height; + + // reallocate buffer if there is a size change or if we haven't allocated one yet. We probably can do this + // somewhere else. + if (!mImageExposeBuffer || + (mImageExposeBufferSize.width * mImageExposeBufferSize.height < mWindow->width * mWindow->height)) { + if (mImageExposeBuffer) + free(mImageExposeBuffer); + + mImageExposeBuffer = (unsigned char*) malloc (mWindow->width * mWindow->height * 4); + mImageExposeBufferSize = gfxIntSize(mWindow->width, mWindow->height); + } + + NS_ENSURE_TRUE(mImageExposeBuffer, NS_ERROR_OUT_OF_MEMORY); + + // Because we are reusing mImageExposeBuffer, there might be old bytes. The API NPImageExpose + // expects that the buffer be zero'ed out. + memset(mImageExposeBuffer, 0, mImageExposeBufferSize.height * mImageExposeBufferSize.width * 4); + + nsRefPtr surf = new gfxImageSurface(mImageExposeBuffer, + mImageExposeBufferSize, + mImageExposeBufferSize.width * 4, + gfxASurface::ImageFormatRGB24); + NS_ENSURE_TRUE(surf, NS_ERROR_OUT_OF_MEMORY); + + // Setup temporary context scaled size + imageExpose.stride = surf->Stride(); + imageExpose.data = reinterpret_cast(surf->Data()); + imageExpose.dataSize.width = surf->Width(); + imageExpose.dataSize.height = surf->Height(); + + PRBool eventHandled = PR_FALSE; + // Get Image surface from original context + // Draw plugin content to temp surface + mInstance->HandleEvent(&pluginEvent, &eventHandled); + + if (eventHandled) { + nsRefPtr pat = new gfxPattern(surf); + aContext->NewPath(); + aContext->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWindow->width, mWindow->height), pat); + aContext->Fill(); + } + return NS_OK; +} +#endif + #if defined(MOZ_WIDGET_GTK2) nsresult nsPluginInstanceOwner::Renderer::NativeDraw(GdkDrawable * drawable, diff --git a/modules/plugin/base/public/npapi.h b/modules/plugin/base/public/npapi.h index 756f28f8a0bf..1296c2f8de1b 100644 --- a/modules/plugin/base/public/npapi.h +++ b/modules/plugin/base/public/npapi.h @@ -337,6 +337,10 @@ typedef enum { /* Used for negotiating event models */ , NPPVpluginEventModel = 1001 #endif + +#ifdef MOZ_PLATFORM_HILDON + , NPPVpluginWindowlessLocalBool = 2002 +#endif } NPPVariable; /* @@ -379,6 +383,9 @@ typedef enum { #endif , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ #endif +#ifdef MOZ_PLATFORM_HILDON + , NPNVSupportsWindowlessLocal = 2002 +#endif } NPNVariable; typedef enum { @@ -419,6 +426,21 @@ typedef struct _NPWindow NPWindowType type; /* Is this a window or a drawable? */ } NPWindow; +typedef struct _NPImageExpose +{ + char* data; /* image pointer */ + int32_t stride; /* Stride of data image pointer */ + int32_t depth; /* Depth of image pointer */ + int32_t x; /* Expose x */ + int32_t y; /* Expose y */ + uint32_t width; /* Expose width */ + uint32_t height; /* Expose height */ + NPSize dataSize; /* Data buffer size */ + float translateX; /* translate X matrix value */ + float translateY; /* translate Y matrix value */ + float scaleX; /* scale X matrix value */ + float scaleY; /* scale Y matrix value */ +} NPImageExpose; typedef struct _NPFullPrint { diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index 7e6d9dd74370..bda4031dcdae 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -1980,6 +1980,13 @@ _getvalue(NPP npp, NPNVariable variable, void *result) return NPERR_GENERIC_ERROR; } +#ifdef MOZ_PLATFORM_HILDON + case NPNVSupportsWindowlessLocal: { + *(NPBool*)result = PR_TRUE; + return NPERR_NO_ERROR; + } +#endif + #ifdef XP_MACOSX case NPNVpluginDrawingModel: { if (npp) { @@ -2103,7 +2110,12 @@ _setvalue(NPP npp, NPPVariable variable, void *result) return inst->SetWindowless(bWindowless); #endif } - +#ifdef MOZ_PLATFORM_HILDON + case NPPVpluginWindowlessLocalBool: { + NPBool bWindowlessLocal = (result != nsnull); + return inst->SetWindowlessLocal(bWindowlessLocal); + } +#endif case NPPVpluginTransparentBool: { NPBool bTransparent = (result != nsnull); return inst->SetTransparent(bTransparent); diff --git a/modules/plugin/base/src/nsNPAPIPluginInstance.cpp b/modules/plugin/base/src/nsNPAPIPluginInstance.cpp index de3d24c36664..9fdf4c6b5591 100644 --- a/modules/plugin/base/src/nsNPAPIPluginInstance.cpp +++ b/modules/plugin/base/src/nsNPAPIPluginInstance.cpp @@ -881,6 +881,7 @@ nsNPAPIPluginInstance::nsNPAPIPluginInstance(NPPluginFuncs* callbacks, #endif #endif mWindowless(PR_FALSE), + mWindowlessLocal(PR_FALSE), mTransparent(PR_FALSE), mStarted(PR_FALSE), mCached(PR_FALSE), @@ -1382,6 +1383,14 @@ NS_IMETHODIMP nsNPAPIPluginInstance::HandleEvent(void* event, PRBool* handled) NS_IMETHODIMP nsNPAPIPluginInstance::GetValueFromPlugin(NPPVariable variable, void* value) { +#ifdef MOZ_PLATFORM_HILDON + // The maemo flash plugin does not remember this. It sets the + // value, but doesn't support the get value. + if (variable == NPPVpluginWindowlessLocalBool) { + *(NPBool*)value = mWindowlessLocal; + return NS_OK; + } +#endif nsresult res = NS_OK; if (mCallbacks->getvalue && mStarted) { PluginDestructionGuard guard(this); @@ -1421,6 +1430,12 @@ NPError nsNPAPIPluginInstance::SetWindowless(PRBool aWindowless) return NPERR_NO_ERROR; } +NPError nsNPAPIPluginInstance::SetWindowlessLocal(PRBool aWindowlessLocal) +{ + mWindowlessLocal = aWindowlessLocal; + return NPERR_NO_ERROR; +} + NPError nsNPAPIPluginInstance::SetTransparent(PRBool aTransparent) { mTransparent = aTransparent; diff --git a/modules/plugin/base/src/nsNPAPIPluginInstance.h b/modules/plugin/base/src/nsNPAPIPluginInstance.h index 533f67f371bb..2b12e66fa6a2 100644 --- a/modules/plugin/base/src/nsNPAPIPluginInstance.h +++ b/modules/plugin/base/src/nsNPAPIPluginInstance.h @@ -86,6 +86,8 @@ public: NPError SetWindowless(PRBool aWindowless); + NPError SetWindowlessLocal(PRBool aWindowlessLocal); + NPError SetTransparent(PRBool aTransparent); NPError SetWantsAllNetworkStreams(PRBool aWantsAllNetworkStreams); @@ -149,6 +151,7 @@ protected: // these are used to store the windowless properties // which the browser will later query PRPackedBool mWindowless; + PRPackedBool mWindowlessLocal; PRPackedBool mTransparent; PRPackedBool mStarted; PRPackedBool mCached;