From 47af6a8370124efcb434a891f09c5b6ea060e0b8 Mon Sep 17 00:00:00 2001 From: "sfraser%netscape.com" Date: Fri, 25 Oct 2002 20:15:29 +0000 Subject: [PATCH] Fix bug 176649 (Chimera plugin issues). Plugins drawing over chrome (bug 172688) Plugins showing through tabs (bug 158018, bug 156583) Plugins not drawing initially on page load (bug 147728, bug 161378) Bugs _not_ fixed: Visual corruption when scrolling with QT movie (bug 160435) Crashes when loading plugins which are offscreen (bug 161378), tho it seems much less easy to reproduce now. Quick summary of changes: Added nsIPluginWidget to allow plugin code to get the widget clip rectangle and origin. Fixes drawing over chrome for plugins in iframes. Always use [mView qdPort], not the WindowRef port, for gecko rendering (making nsIRenderingContexts). Only use the WindowRef port for plugin drawing. Fixes drawing over chrome. Always call SetPortVisibleRegion() before plugin drawing, because we don't know what part of the BeginUpdate/EndUpdate cycle we're in. Keep track of whether views are in the frontmost tab (i.e. have a window), and hide/show views immediately on tab switching, rather than on the next timer fire. Fixes plugins stomping through tabs (mostly). Add smarts to FixUpPluginWindow() in nsObjectFrame so that it knows when it's Ok to display the plugin (after a ::Paint()). Fixes plugins drawing in the wrong place/not drawing on initial page load. git-svn-id: svn://10.0.0.236/branches/CHIMERA_M1_0_1_BRANCH@132538 18797224-902f-48f8-a5cc-f745e15eee43 --- .../plugin/base/src/ns4xPluginInstance.cpp | 60 ++++-- .../plugin/base/src/ns4xPluginInstance.h | 5 + .../plugin/base/src/nsPluginViewer.cpp | 184 +++++++++++------- 3 files changed, 162 insertions(+), 87 deletions(-) diff --git a/mozilla/modules/plugin/base/src/ns4xPluginInstance.cpp b/mozilla/modules/plugin/base/src/ns4xPluginInstance.cpp index a29f9cf389b..9305f4d47bd 100644 --- a/mozilla/modules/plugin/base/src/ns4xPluginInstance.cpp +++ b/mozilla/modules/plugin/base/src/ns4xPluginInstance.cpp @@ -49,6 +49,7 @@ #include "nsPluginSafety.h" #include "nsIPref.h" // needed for NS_TRY_SAFE_CALL_* #include "nsPluginLogging.h" +#include "nsIPluginWidget.h" #if defined(MOZ_WIDGET_GTK) #include @@ -363,6 +364,10 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, // do not read more that supplier wants us to read bytesToRead = length; } + +#if defined(XP_MAC) || defined(XP_MACOSX) + mInst->SetupForPluginDrawing(); +#endif do { @@ -463,6 +468,11 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo, } // end of for(;;) } while ((PRInt32)(length) > 0); + +#if defined(XP_MAC) || defined(XP_MACOSX) + mInst->DonePluginDrawing(); +#endif + return rv; } @@ -618,6 +628,27 @@ ns4xPluginInstance :: IsStarted(void) } +/////////////////////////////////////////////////////////////////////////////// +nsresult +ns4xPluginInstance::SetupForPluginDrawing() +{ +#if defined(XP_MAC) || defined(XP_MACOSX) + ::SetPort(mWindow->window->port); +#endif + return NS_OK; +} + +/////////////////////////////////////////////////////////////////////////////// +nsresult +ns4xPluginInstance::DonePluginDrawing() +{ +#if defined(XP_MAC) || defined(XP_MACOSX) + +#endif + return NS_OK; +} + + //////////////////////////////////////////////////////////////////////// NS_IMETHODIMP ns4xPluginInstance::Initialize(nsIPluginInstancePeer* peer) { @@ -1012,8 +1043,8 @@ NS_IMETHODIMP ns4xPluginInstance::SetWindow(nsPluginWindow* window) NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, - ("NPP SetWindow called: this=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d], return=%d\n", - this, window->x, window->y, window->width, window->height, + ("NPP SetWindow called: this=%p, window=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d], return=%d\n", + this, *window->window, window->x, window->y, window->width, window->height, window->clipRect.top, window->clipRect.bottom, window->clipRect.left, window->clipRect.right, error)); // XXX In the old code, we'd just ignore any errors coming @@ -1122,25 +1153,12 @@ NS_IMETHODIMP ns4xPluginInstance::HandleEvent(nsPluginEvent* event, PRBool* hand if (fCallbacks->event) { #if defined(XP_MAC) || defined(XP_MACOSX) -#if 0 - switch(event->event->what) { - case updateEvt: - if (mWindow) { - GrafPtr port; - GetPort(&port); - if (port != mWindow->window->port) printf("[!!! port isn't set correctly !!!!]\n"); - RGBColor oldColor; - RGBColor green = { 0, 0xFFFF, 0 }; - GetForeColor(&oldColor); - RGBForeColor(&green); - PaintRect((Rect*)&mWindow->clipRect); - // ::QDFlushPortBuffer(port, NULL); - RGBForeColor(&oldColor); - // printf("[portx = %d, porty = %d]\n", mWindow->window->portx, mWindow->window->porty); - } - break; - } -#endif + + NPP_PLUGIN_LOG(PLUGIN_LOG_NORMAL, + ("CallNPP_HandleEventProc called: this=%p, [x=%d,y=%d,w=%d,h=%d], clip[t=%d,b=%d,l=%d,r=%d]\n", + this, mWindow->x, mWindow->y, mWindow->width, mWindow->height, + mWindow->clipRect.top, mWindow->clipRect.bottom, mWindow->clipRect.left, mWindow->clipRect.right)); + result = CallNPP_HandleEventProc(fCallbacks->event, &fNPP, (void*) event->event); diff --git a/mozilla/modules/plugin/base/src/ns4xPluginInstance.h b/mozilla/modules/plugin/base/src/ns4xPluginInstance.h index 17b166c0b46..51728625c4a 100644 --- a/mozilla/modules/plugin/base/src/ns4xPluginInstance.h +++ b/mozilla/modules/plugin/base/src/ns4xPluginInstance.h @@ -153,6 +153,11 @@ public: // cache this 4.x plugin like an XPCOM plugin nsresult SetCached(PRBool aCache) { mCached = aCache; return NS_OK; }; + // only used on Mac; called to ensure that the plugin can draw whenever + // we call into it + nsresult SetupForPluginDrawing(); + nsresult DonePluginDrawing(); + protected: nsresult InitializePlugin(nsIPluginInstancePeer* peer); diff --git a/mozilla/modules/plugin/base/src/nsPluginViewer.cpp b/mozilla/modules/plugin/base/src/nsPluginViewer.cpp index 81f224f9567..72c755b7463 100644 --- a/mozilla/modules/plugin/base/src/nsPluginViewer.cpp +++ b/mozilla/modules/plugin/base/src/nsPluginViewer.cpp @@ -53,6 +53,7 @@ #include "nsIContentViewerEdit.h" #include "nsIWebBrowserPrint.h" #include "nsIWidget.h" +#include "nsIPluginWidget.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsIInterfaceRequestor.h" @@ -650,6 +651,7 @@ PluginViewerImpl::SetBounds(const nsRect& aBounds) #if defined(XP_MAC) || defined(XP_MACOSX) // On Mac we also need to add in the widget offset to the plugin window mOwner->FixUpPluginWindow(); + mWindow->Invalidate(PR_FALSE); #endif inst->SetWindow(win); } @@ -679,6 +681,7 @@ PluginViewerImpl::Move(PRInt32 aX, PRInt32 aY) #if defined(XP_MAC) || defined(XP_MACOSX) // On Mac we also need to add in the widget offset to the plugin window mOwner->FixUpPluginWindow(); + mWindow->Invalidate(PR_FALSE); #endif inst->SetWindow(win); } @@ -1038,7 +1041,30 @@ PluginListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, if (nsnull == mNextStream) { return NS_ERROR_FAILURE; } - return mNextStream->OnDataAvailable(request, ctxt, inStr, sourceOffset, count); + + nsresult rv = NS_OK; + +#if defined (XP_MAC) || defined(XP_MACOSX) + NS_ASSERTION(mViewer, "Need plugin viewer"); + nsCOMPtr pluginWidget = do_QueryInterface(mViewer->mWindow); + PRBool startDrawCalled = PR_FALSE; + + if (pluginWidget) + { + rv = pluginWidget->StartDrawPlugin(); + NS_ASSERTION(NS_SUCCEEDED(rv), "StartDrawPlugin failed in OnDataAvailable!"); + startDrawCalled = NS_SUCCEEDED(rv); + } +#endif + + rv = mNextStream->OnDataAvailable(request, ctxt, inStr, sourceOffset, count); + +#if defined (XP_MAC) || defined(XP_MACOSX) + if (pluginWidget && startDrawCalled) + pluginWidget->EndDrawPlugin(); +#endif + + return rv; } //---------------------------------------------------------------------- @@ -1291,38 +1317,48 @@ nsEventStatus pluginInstanceOwner::ProcessEvent(const nsGUIEvent& anEvent) return rv; #if defined(XP_MAC) || defined(XP_MACOSX) - //if (mWidget != NULL) { // check for null mWidget - EventRecord* event = (EventRecord*)anEvent.nativeMsg; - if (event == NULL || event->what == nullEvent || - anEvent.message == NS_CONTEXTMENU_MESSAGE_START) { - EventRecord macEvent; - GUItoMacEvent(anEvent, macEvent); - event = &macEvent; - if (event->what == updateEvt) { - // Add in child windows absolute position to get make the dirty rect - // relative to the top-level window. - nsPluginPort* pluginPort = FixUpPluginWindow(); - if (pluginPort) { - EventRecord updateEvent; - InitializeEventRecord(&updateEvent); - updateEvent.what = updateEvt; - updateEvent.message = UInt32(pluginPort->port); - - nsPluginEvent pluginEvent = { &updateEvent, nsPluginPlatformWindowRef(pluginPort->port) }; - PRBool eventHandled = PR_FALSE; - mInstance->HandleEvent(&pluginEvent, &eventHandled); + + nsCOMPtr pluginWidget = do_QueryInterface(mWindow); + if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) + { + //if (mWidget != NULL) { // check for null mWidget + EventRecord* event = (EventRecord*)anEvent.nativeMsg; + if (event == NULL || event->what == nullEvent || + anEvent.message == NS_CONTEXTMENU_MESSAGE_START) { + EventRecord macEvent; + GUItoMacEvent(anEvent, macEvent); + event = &macEvent; + if (event->what == updateEvt) { + // Add in child windows absolute position to get make the dirty rect + // relative to the top-level window. + nsPluginPort* pluginPort = FixUpPluginWindow(); + if (pluginPort) { + EventRecord updateEvent; + InitializeEventRecord(&updateEvent); + updateEvent.what = updateEvt; + updateEvent.message = UInt32(pluginPort->port); + + nsPluginEvent pluginEvent = { &updateEvent, nsPluginPlatformWindowRef(pluginPort->port) }; + PRBool eventHandled = PR_FALSE; + mInstance->HandleEvent(&pluginEvent, &eventHandled); + } } + rv = nsEventStatus_eConsumeNoDefault; } - return nsEventStatus_eConsumeNoDefault; - - } - nsPluginPort* port = (nsPluginPort*)mWindow->GetNativeData(NS_NATIVE_PLUGIN_PORT); - nsPluginEvent pluginEvent = { event, nsPluginPlatformWindowRef(port->port) }; - PRBool eventHandled = PR_FALSE; - mInstance->HandleEvent(&pluginEvent, &eventHandled); - if (eventHandled && anEvent.message != NS_MOUSE_LEFT_BUTTON_DOWN) - rv = nsEventStatus_eConsumeNoDefault; - // } + else + { + nsPluginPort* port = (nsPluginPort*)mWindow->GetNativeData(NS_NATIVE_PLUGIN_PORT); + nsPluginEvent pluginEvent = { event, nsPluginPlatformWindowRef(port->port) }; + PRBool eventHandled = PR_FALSE; + mInstance->HandleEvent(&pluginEvent, &eventHandled); + if (eventHandled && anEvent.message != NS_MOUSE_LEFT_BUTTON_DOWN) + rv = nsEventStatus_eConsumeNoDefault; + } + // } + + pluginWidget->EndDrawPlugin(); + } + #endif //~~~ @@ -1348,33 +1384,31 @@ NS_IMETHODIMP_(void) pluginInstanceOwner::Notify(nsITimer* /* timer */) // validate the plugin clipping information by syncing the plugin window info to // reflect the current widget location. This makes sure that everything is updated // correctly in the event of scrolling in the window. - if (mInstance != NULL) { - nsPluginPort* pluginPort = FixUpPluginWindow(); - if (pluginPort) { - EventRecord idleEvent; - InitializeEventRecord(&idleEvent); - idleEvent.what = nullEvent; - - // give a bogus 'where' field of our null event when hidden, so Flash - // won't respond to mouse moves in other tabs, see bug 120875 - if (!mWidgetVisible) - idleEvent.where.h = idleEvent.where.v = 20000; - - nsPluginEvent pluginEvent = { &idleEvent, nsPluginPlatformWindowRef(pluginPort->port) }; - - PRBool eventHandled = PR_FALSE; - mInstance->HandleEvent(&pluginEvent, &eventHandled); + if (mInstance != NULL) + { + nsCOMPtr pluginWidget = do_QueryInterface(mWindow); + if (pluginWidget && NS_SUCCEEDED(pluginWidget->StartDrawPlugin())) + { + nsPluginPort* pluginPort = FixUpPluginWindow(); + if (pluginPort) { + EventRecord idleEvent; + InitializeEventRecord(&idleEvent); + idleEvent.what = nullEvent; + + // give a bogus 'where' field of our null event when hidden, so Flash + // won't respond to mouse moves in other tabs, see bug 120875 + if (!mWidgetVisible) + idleEvent.where.h = idleEvent.where.v = 20000; + + nsPluginEvent pluginEvent = { &idleEvent, nsPluginPlatformWindowRef(pluginPort->port) }; + + PRBool eventHandled = PR_FALSE; + mInstance->HandleEvent(&pluginEvent, &eventHandled); + } + + pluginWidget->EndDrawPlugin(); } } - -#ifndef REPEATING_TIMERS - // reprime the timer? currently have to create a new timer for each call, which is - // kind of wasteful. need to get periodic timers working on all platforms. - nsresult rv; - mPluginTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); - if (NS_SUCCEEDED(rv)) - mPluginTimer->Init(this, 1020 / 60); -#endif // REPEATING_TIMERS #endif // XP_MAC } @@ -1473,31 +1507,49 @@ nsPluginPort* pluginInstanceOwner::FixUpPluginWindow() { if (mWindow) { nsPluginPort* pluginPort = GetPluginPort(); - nscoord absWidgetX = 0; - nscoord absWidgetY = 0; + nsRect widgetClip(0, 0, 0, 0); PRBool isVisible = PR_TRUE; - GetWidgetPosClipAndVis(mWindow, absWidgetX, absWidgetY, widgetClip, isVisible); #if defined(MOZ_WIDGET_COCOA) + nsPoint pluginOrigin; + nsCOMPtr pluginWidget = do_QueryInterface(mWindow); + pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin); + + // check widget visibility (do we really have to do this here?) + nsCOMPtr widget = mWindow; + while (widget) + { + PRBool widgetVisible; + widget->IsVisible(widgetVisible); + isVisible &= widgetVisible; + + widget = getter_AddRefs(widget->GetParent()); + } + + if (!isVisible) + widgetClip.Empty(); + // set the port coordinates mPluginWindow.x = -pluginPort->portx; mPluginWindow.y = -pluginPort->porty; - widgetClip.x += mPluginWindow.x - absWidgetX; - widgetClip.y += mPluginWindow.y - absWidgetY; #else + nscoord absWidgetX = 0; + nscoord absWidgetY = 0; + GetWidgetPosClipAndVis(mWindow, absWidgetX, absWidgetY, widgetClip, isVisible); // set the port coordinates mPluginWindow.x = absWidgetX; mPluginWindow.y = absWidgetY; #endif // fix up the clipping region - mPluginWindow.clipRect.top = widgetClip.y; - mPluginWindow.clipRect.left = widgetClip.x; - mPluginWindow.clipRect.bottom = mPluginWindow.clipRect.top + widgetClip.height; - mPluginWindow.clipRect.right = mPluginWindow.clipRect.left + widgetClip.width; + mPluginWindow.clipRect.top = widgetClip.y; + mPluginWindow.clipRect.left = widgetClip.x; + mPluginWindow.clipRect.bottom = mPluginWindow.clipRect.top + widgetClip.height; + mPluginWindow.clipRect.right = mPluginWindow.clipRect.left + widgetClip.width; - if (mWidgetVisible != isVisible) { + if (mWidgetVisible != isVisible) + { mWidgetVisible = isVisible; // must do this to disable async Java Applet drawing if (isVisible) {