Bug 311618, Crash [@ QDFlushPortBuffer]. Replumb the flush manager as an XPCOM service so that other components can cancel scheduled flushes when ports are going away. Away goes trouble down the drain. Camino/koko-widget only. r=pink sr=smfr a/1.8=asa

git-svn-id: svn://10.0.0.236/trunk@182170 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
mark%moxienet.com
2005-10-13 16:48:16 +00:00
parent bb5d439580
commit 0adbddf7a0
7 changed files with 181 additions and 191 deletions

View File

@@ -74,6 +74,10 @@ XPIDLSRCS += nsIPrintSettingsX.idl \
$(NULL)
endif
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
XPIDLSRCS += nsIQDFlushManager.idl
endif
ifeq ($(MOZ_GFX_TOOLKIT),windows)
XPIDLSRCS += nsIPrintSettingsWin.idl
endif

View File

@@ -0,0 +1,75 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** 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 supposed to avoid exccessive QuickDraw flushes.
*
* The Initial Developer of the Original Code is
* Mark Mentovai <mark@moxienet.com>.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 ***** */
#include "nsISupports.idl"
%{ C++
#include <Carbon/Carbon.h>
%}
native CGrafPtr(CGrafPtr);
native RgnHandle(RgnHandle);
/**
* nsIQDFlushManager is responsible for rate-limiting QuickDraw buffer
* flushes. Think of it as a plumber in a time of rationing. It's
* expected to be used as a singleton doled out by the service manager.
*/
[uuid(40352CE3-9D15-4643-8CBF-71DA61650F13)]
interface nsIQDFlushManager : nsISupports
{
/**
* Flushes the port buffer, a la QDFlushPortBuffer. If the buffer has
* been flushed too recently, the region to flush is instead added to
* the dirty region, and a buffer flush will be scheduled for an
* appropriate time.
*
* @param aPort the QuickDraw port to flush
*
* @param aRegion the region to flush or mark as dirty
*/
void flushPortBuffer(in CGrafPtr aPort, in RgnHandle aRegion);
/**
* Cancels a pending flush scheduled by calling flushPortBuffer. This
* method is suitable to call when a port is destroyed.
*
* @param aPort the QuickDraw port to not flush
*/
void removePort(in CGrafPtr aPort);
};

View File

@@ -57,6 +57,9 @@
#include "nsCOMPtr.h"
#include "nsUnicodeMappingUtil.h"
#include "gfxImageFrame.h"
#ifdef MOZ_WIDGET_COCOA
#include "nsQDFlushManager.h"
#endif
#include "nsIGenericFactory.h"
@@ -76,6 +79,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFontEnumeratorMac)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFontList)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerMac)
NS_GENERIC_FACTORY_CONSTRUCTOR(gfxImageFrame)
#ifdef MOZ_WIDGET_COCOA
NS_GENERIC_FACTORY_CONSTRUCTOR(nsQDFlushManager)
#endif
static NS_IMETHODIMP
nsScriptableRegionConstructor(nsISupports* aOuter, REFNSIID aIID, void** aResult)
@@ -155,7 +161,13 @@ static const nsModuleComponentInfo components[] =
{ "windows image frame",
GFX_IMAGEFRAME_CID,
"@mozilla.org/gfx/image/frame;2",
gfxImageFrameConstructor, }
gfxImageFrameConstructor, },
#ifdef MOZ_WIDGET_COCOA
{ NS_QDFLUSHMANAGER_CLASSNAME,
NS_QDFLUSHMANAGER_CID,
NS_QDFLUSHMANAGER_CONTRACTID,
nsQDFlushManagerConstructor },
#endif
};
PR_STATIC_CALLBACK(void)

View File

@@ -38,77 +38,16 @@
#include "nsQDFlushManager.h"
#include "nsComponentManagerUtils.h"
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "nsCRT.h"
class nsQDFlushPort : public nsITimerCallback
{
// nsQDFlushManager is responsible for maintaining the list of port objects.
friend class nsQDFlushManager;
protected:
nsQDFlushPort(CGrafPtr aPort);
~nsQDFlushPort();
void Init(CGrafPtr aPort);
void Destroy();
void FlushPortBuffer(RgnHandle aRegion);
PRInt64 TimeUntilFlush(AbsoluteTime aNow);
NS_DECL_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
// To use the display's refresh rate as the update Hz, see
// http://developer.apple.com/documentation/Performance/Conceptual/Drawing/Articles/FlushingContent.html .
// Here, use a hard-coded 30 Hz instead.
static const PRUint32 kRefreshRateHz = 30; // Maximum number of updates
// per second
nsQDFlushPort* mNext; // Next object in list
CGrafPtr mPort; // Associated port
AbsoluteTime mLastFlushTime; // Last QDFlushPortBuffer call
nsCOMPtr<nsITimer> mFlushTimer; // Timer for scheduled flush
PRPackedBool mFlushTimerRunning; // Is it?
};
class nsQDFlushObserver : public nsIObserver
{
// nsQDFlushManager is responsible for creating the observer.
friend class nsQDFlushManager;
protected:
nsQDFlushObserver(nsQDFlushManager* aParent);
~nsQDFlushObserver();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
nsQDFlushManager* mParent; // Parent object
};
// nsQDFlushManager
// protected static
nsQDFlushManager* nsQDFlushManager::sQDFlushManager = nsnull;
nsQDFlushObserver* nsQDFlushManager::sQDFlushObserver = nsnull;
// nsQDFlushManager() constructor
//
// If you create your own object, you are responsible for freeing it. Once
// freed, it will free the attached port objects.
//
// If you work through the static object by calling through the static
// sQDFlushPortBuffer method, the static object will be created dynamically
// at first call and will be freed automatically at shutdown.
nsQDFlushManager::nsQDFlushManager()
: mPortList(nsnull)
{
}
// ~nsQDFlushManager() destructor
//
// See the note about object creation and destruction in the comment
// preceding the constructor.
nsQDFlushManager::~nsQDFlushManager()
{
nsQDFlushPort* port = mPortList;
@@ -121,34 +60,6 @@ nsQDFlushManager::~nsQDFlushManager()
}
}
// FlushPortBuffer(aPort, aRegion)
//
// The public entry point for object-based calls. Calls
// QDFlushPortBuffer(aPort, aRegion) if aPort hasn't been flushed too
// recently. If it has been, calls QDAddRegionToDirtyRegion(aPort, aRegion)
// and if no flush has been scheduled, schedules a flush for the appropriate
// time.
//
// public
void
nsQDFlushManager::FlushPortBuffer(CGrafPtr aPort, RgnHandle aRegion)
{
CreateOrGetPort(aPort)->FlushPortBuffer(aRegion);
}
// sFlushPortBuffer(aPort, aRegion)
//
// The public entry point for calls into the static flush manager. Gets
// the static object, creating it if necessary, and then calls into
// FlushPortBuffer above.
//
// public static
void
nsQDFlushManager::sFlushPortBuffer(CGrafPtr aPort, RgnHandle aRegion)
{
GetStaticQDFlushManager()->FlushPortBuffer(aPort, aRegion);
}
// CreateOrGetPort(aPort)
//
// Walks through the list of port objects and returns the one corresponding to
@@ -203,15 +114,33 @@ nsQDFlushManager::CreateOrGetPort(CGrafPtr aPort)
return port;
}
NS_IMPL_ISUPPORTS1(nsQDFlushManager, nsIQDFlushManager)
// nsIQDFlushManager implementation
// FlushPortBuffer(aPort, aRegion)
//
// The public entry point for object-based calls. Calls
// QDFlushPortBuffer(aPort, aRegion) if aPort hasn't been flushed too
// recently. If it has been, calls QDAddRegionToDirtyRegion(aPort, aRegion)
// and if no flush has been scheduled, schedules a flush for the appropriate
// time.
//
// public
NS_IMETHODIMP
nsQDFlushManager::FlushPortBuffer(CGrafPtr aPort, RgnHandle aRegion)
{
CreateOrGetPort(aPort)->FlushPortBuffer(aRegion);
return NS_OK;
}
// RemovePort(aPort)
//
// Walks through the list of port objects and removes the one corresponding to
// aPort, if it exists.
//
// Presently unused.
//
// protected
void
// public
NS_IMETHODIMP
nsQDFlushManager::RemovePort(CGrafPtr aPort)
{
// Traversal is as in CreateOrGetPort.
@@ -228,56 +157,11 @@ nsQDFlushManager::RemovePort(CGrafPtr aPort)
// mPortList. That makes it easy to snip the old object out by
// setting it to the follower.
*portPtr = next;
return;
return NS_OK;
}
portPtr = &port->mNext;
}
}
// GetStaticQDFlushManager()
//
// Most calls through nsQDFlushManager are expected to be made through
// a global object, through the static sQDFlushPort method. Because
// constructors and destructors on static objects are distrusted, each
// call into sQDFlushPort obtains the static object by calling here.
// If the object does not yet exist, it is created. To handle destruction,
// a shutdown observer is added. The observer handles teardown of the
// static manager object and all attached port objects.
//
// protected static
nsQDFlushManager*
nsQDFlushManager::GetStaticQDFlushManager()
{
if (!sQDFlushManager)
{
// The static flush manager has not yet been initialized. Create it.
sQDFlushManager = new nsQDFlushManager();
NS_ASSERTION(sQDFlushManager, "failed to create flush manager");
if (!sQDFlushManager)
{
// Early return, avoid creating a useless observer.
return nsnull;
}
// Create a shutdown observer to handle destruction.
sQDFlushObserver = new nsQDFlushObserver(sQDFlushManager);
NS_ASSERTION(sQDFlushObserver, "failed to create observer");
if (sQDFlushObserver)
{
// register for shutdown
nsresult rv;
nsCOMPtr<nsIObserverService> observerService(
do_GetService("@mozilla.org/observer-service;1", &rv));
if (NS_SUCCEEDED(rv))
{
// There's not much we can or should do if this fails.
observerService->AddObserver(sQDFlushObserver,
NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
}
}
}
return sQDFlushManager;
return NS_OK;
}
// nsQDFlushPort
@@ -411,31 +295,3 @@ nsQDFlushPort::Notify(nsITimer* aTimer)
return NS_OK;
}
// nsQDFlushObserver
nsQDFlushObserver::nsQDFlushObserver(nsQDFlushManager* aParent)
: mParent(aParent)
{
}
nsQDFlushObserver::~nsQDFlushObserver()
{
}
// nsIObserver implementation
NS_IMPL_ISUPPORTS1(nsQDFlushObserver, nsIObserver)
// Observe(aSubject, aTopic, aData)
//
// Shutdown callback. Delete static object and any attached port objects.
NS_IMETHODIMP
nsQDFlushObserver::Observe(nsISupports* aSubject, const char* aTopic,
const PRUnichar* aData)
{
NS_ASSERTION(!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID,aTopic),
"Shutdown observer called with wrong topic\n");
delete mParent;
return NS_OK;
}

View File

@@ -41,44 +41,69 @@
#include "nscore.h"
#include "nsCOMPtr.h"
#include "nsIQDFlushManager.h"
#include "nsITimer.h"
#include "nsIObserver.h"
#include <Carbon/Carbon.h>
// The expected use is to replace these calls:
// ::QDFlushPortBuffer(port, region)
// with these:
// nsQDFlushManager::sFlushPortBuffer(port,region)
// nsCOMPtr<nsIQDFlushManager> qdFlushManager =
// do_GetService("@mozilla.org/gfx/qdflushmanager;1");
// qdFlushManager->FlushPortBuffer(port, region);
// and at port destruction time:
// qdFlushManager->RemovePort(port)
// These subservient classes are defined in nsQDFlushManager.cpp.
class nsQDFlushPort;
class nsQDFlushObserver;
class NS_EXPORT nsQDFlushManager
class nsQDFlushPort : public nsITimerCallback
{
// nsQDFlushObserver is responsible for destruction of the static object.
friend class nsQDFlushObserver;
// nsQDFlushManager is responsible for maintaining the list of port objects.
friend class nsQDFlushManager;
NS_DECL_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
protected:
nsQDFlushPort(CGrafPtr aPort);
~nsQDFlushPort();
void Init(CGrafPtr aPort);
void Destroy();
void FlushPortBuffer(RgnHandle aRegion);
PRInt64 TimeUntilFlush(AbsoluteTime aNow);
// To use the display's refresh rate as the update Hz, see
// http://developer.apple.com/documentation/Performance/Conceptual/Drawing/Articles/FlushingContent.html .
// Here, use a hard-coded 30 Hz instead.
static const PRUint32 kRefreshRateHz = 30; // Maximum number of updates
// per second
nsQDFlushPort* mNext; // Next object in list
CGrafPtr mPort; // Associated port
AbsoluteTime mLastFlushTime; // Last QDFlushPortBuffer call
nsCOMPtr<nsITimer> mFlushTimer; // Timer for scheduled flush
PRPackedBool mFlushTimerRunning; // Is it?
};
class NS_EXPORT nsQDFlushManager : public nsIQDFlushManager
{
NS_DECL_ISUPPORTS
NS_DECL_NSIQDFLUSHMANAGER
public:
nsQDFlushManager();
~nsQDFlushManager();
void FlushPortBuffer(CGrafPtr aPort,
RgnHandle aRegion);
static void sFlushPortBuffer(CGrafPtr aPort,
RgnHandle aRegion);
protected:
nsQDFlushPort* CreateOrGetPort(CGrafPtr aPort);
void RemovePort(CGrafPtr aPort);
static nsQDFlushManager* GetStaticQDFlushManager();
nsQDFlushPort* mPortList; // Head of list
static nsQDFlushManager* sQDFlushManager; // Static object
static nsQDFlushObserver* sQDFlushObserver; // Cleanup for static object
};
// 6F91262A-CF9E-4DDD-AA01-7A1FCCF14281
#define NS_QDFLUSHMANAGER_CLASSNAME "QuickDraw Buffer Flusher"
#define NS_QDFLUSHMANAGER_CID \
{0x6F91262A, 0xCF9E, 0x4DDD, {0xAA, 0x01, 0x7A, 0x1F, 0xCC, 0xF1, 0x42, 0x81}}
#define NS_QDFLUSHMANAGER_CONTRACTID "@mozilla.org/gfx/qdflushmanager;1"
#endif /* nsQDFlushManager_h___ */

View File

@@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */
#include "nsIInterfaceRequestorUtils.h"
#include "nsIServiceManager.h"
#include "nsRenderingContextMac.h"
#include "nsDeviceContextMac.h"
#include "nsFontMetricsMac.h"
@@ -50,9 +51,12 @@
#include "nsVoidArray.h"
#include "nsGfxCIID.h"
#include "nsGfxUtils.h"
#include "nsQDFlushManager.h"
#include "nsCOMPtr.h"
#ifdef MOZ_WIDGET_COCOA
#include "nsIQDFlushManager.h"
#endif
#include "plhash.h"
#include <FixMath.h>
@@ -1426,7 +1430,10 @@ nsRenderingContextMac::FlushRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord
::SetRectRgn(rgn, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
nsQDFlushManager::sFlushPortBuffer(mPort, rgn);
nsCOMPtr<nsIQDFlushManager> qdFlushManager =
do_GetService("@mozilla.org/gfx/qdflushmanager;1");
if (qdFlushManager)
qdFlushManager->FlushPortBuffer(mPort, rgn);
}
#endif
return NS_OK;

View File

@@ -53,10 +53,12 @@
#include "nsIEventSink.h"
#include "nsIScrollableView.h"
#include "nsIInterfaceRequestor.h"
#include "nsIServiceManager.h"
#include "nsCarbonHelpers.h"
#include "nsGfxUtils.h"
#include "nsMacResources.h"
#include "nsIQDFlushManager.h"
#import "nsCursorManager.h"
#import "nsWindowMap.h"
@@ -465,6 +467,15 @@ void nsChildView::TearDownView()
[(NSView*)responder isDescendantOf:mView])
[win makeFirstResponder: [mView superview]];
GrafPtr curPort = GetChildViewQuickDrawPort();
if (curPort)
{
nsCOMPtr<nsIQDFlushManager> qdFlushManager =
do_GetService("@mozilla.org/gfx/qdflushmanager;1");
if (qdFlushManager)
qdFlushManager->RemovePort(curPort);
}
[mView removeFromSuperviewWithoutNeedingDisplay];
[mView release];
mView = nil;