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
This commit is contained in:
sfraser%netscape.com
2002-10-25 20:15:29 +00:00
parent 404e336322
commit 47af6a8370
3 changed files with 162 additions and 87 deletions

View File

@@ -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 <gdk/gdk.h>
@@ -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);

View File

@@ -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);

View File

@@ -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<nsIPluginWidget> 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<nsIPluginWidget> 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<nsIPluginWidget> 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<nsIPluginWidget> pluginWidget = do_QueryInterface(mWindow);
pluginWidget->GetPluginClipRect(widgetClip, pluginOrigin);
// check widget visibility (do we really have to do this here?)
nsCOMPtr<nsIWidget> 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) {