Fixing
bug 347743. Delay plugin destruction on windows to get it out of layout frame destruction. r+sr=roc@ocallahan.org
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -117,16 +117,18 @@
#include "nsIClassInfo.h"
#include "nsObjectFrame.h"
#include "nsIObjectFrame.h"
#include "nsPluginNativeWindow.h"
#include "nsPIPluginHost.h"
#include "nsIPluginDocument.h"
+#include "nsThreadUtils.h"
+
#ifdef MOZ_CAIRO_GFX
#include "gfxContext.h"
#endif
// accessibility support
#ifdef ACCESSIBILITY
#include "nsIAccessibilityService.h"
#endif
@@ -327,16 +329,18 @@ public:
NS_IMETHOD DragDrop(nsIDOMEvent* aMouseEvent);
NS_IMETHOD DragGesture(nsIDOMEvent* aMouseEvent);
NS_IMETHOD Drag(nsIDOMEvent* aMouseEvent);
NS_IMETHOD DragEnd(nsIDOMEvent* aMouseEvent);
nsresult Destroy();
+ void PrepareToStop(PRBool aDelayedStop);
+
//nsIEventListener interface
nsEventStatus ProcessEvent(const nsGUIEvent & anEvent);
void Paint(const nsRect& aDirtyRect, PRUint32 ndc = 0);
// nsITimerCallback interface
NS_DECL_NSITIMERCALLBACK
@@ -358,30 +362,39 @@ public:
void SetPluginHost(nsIPluginHost* aHost);
#ifdef XP_MACOSX
NPDrawingModel GetDrawingModel();
WindowRef FixUpPluginWindow(PRInt32 inPaintState);
void GUItoMacEvent(const nsGUIEvent& anEvent, EventRecord* origEvent, EventRecord& aMacEvent);
#endif
+ void SetOwner(nsObjectFrame *aOwner)
+ {
+ mOwner = aOwner;
+ }
+
private:
void FixUpURLS(const nsString &name, nsAString &value);
nsPluginNativeWindow *mPluginWindow;
nsCOMPtr<nsIPluginInstance> mInstance;
nsObjectFrame *mOwner;
nsCOMPtr<nsIContent> mContent;
nsCString mDocumentBase;
char *mTagText;
nsCOMPtr<nsIWidget> mWidget;
nsCOMPtr<nsITimer> mPluginTimer;
nsCOMPtr<nsIPluginHost> mPluginHost;
PRPackedBool mContentFocused;
PRPackedBool mWidgetVisible; // used on Mac to store our widget's visible state
+
+ // If true, destroy the widget on destruction. Used when plugin stop
+ // is being delayed to a safer point in time.
+ PRPackedBool mDestroyWidget;
PRUint16 mNumCachedAttrs;
PRUint16 mNumCachedParams;
char **mCachedAttrParamNames;
char **mCachedAttrParamValues;
nsPluginDOMContextMenuListener * mCXMenuListener; // pointer to wrapper for nsIDOMContextMenuListener
nsresult DispatchKeyToPlugin(nsIDOMEvent* aKeyEvent);
@@ -494,17 +507,17 @@ nsObjectFrame::Init(nsIContent* aCo
void
nsObjectFrame::Destroy()
{
NS_ASSERTION(!mInstantiating, "about to crash due to bug 136927");
// we need to finish with the plugin before native window is destroyed
// doing this in the destructor is too late.
- StopPlugin();
+ StopPluginInternal(PR_TRUE);
nsObjectFrameSuper::Destroy();
}
nsIAtom*
nsObjectFrame::GetType() const
{
return nsGkAtoms::objectFrame;
@@ -1283,17 +1296,17 @@ nsresult nsObjectFrame::GetPluginInstanc
return mInstanceOwner->GetInstance(aPluginInstance);
}
nsresult
nsObjectFrame::PrepareInstanceOwner()
{
// First, have to stop any possibly running plugins.
- StopPlugin();
+ StopPluginInternal(PR_FALSE);
NS_ASSERTION(!mInstanceOwner, "Must not have an instance owner here");
mInstanceOwner = new nsPluginInstanceOwner();
if (!mInstanceOwner)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mInstanceOwner);
@@ -1353,80 +1366,143 @@ nsObjectFrame::Instantiate(const char* a
// said plugin instance.
NotifyContentObjectWrapper();
}
}
return rv;
}
-void
-nsObjectFrame::StopPlugin()
+class nsStopPluginRunnable : public nsRunnable
+{
+public:
+ nsStopPluginRunnable(nsPluginInstanceOwner *aInstanceOwner)
+ : mInstanceOwner(aInstanceOwner)
+ {
+ }
+
+ NS_IMETHOD Run();
+
+private:
+ nsRefPtr<nsPluginInstanceOwner> mInstanceOwner;
+};
+
+static void
+DoStopPlugin(nsPluginInstanceOwner *aInstanceOwner)
{
- if (mInstanceOwner != nsnull) {
- nsCOMPtr<nsIPluginInstance> inst;
- mInstanceOwner->GetInstance(*getter_AddRefs(inst));
- if (inst) {
- nsPluginWindow *win;
- mInstanceOwner->GetWindow(win);
- nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
- nsCOMPtr<nsIPluginInstance> nullinst;
-
- PRBool doCache = PR_TRUE;
- PRBool doCallSetWindowAfterDestroy = PR_FALSE;
-
- // first, determine if the plugin wants to be cached
- inst->GetValue(nsPluginInstanceVariable_DoCacheBool,
- (void *) &doCache);
- if (!doCache) {
- // then determine if the plugin wants Destroy to be called after
- // Set Window. This is for bug 50547.
- inst->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
- (void *) &doCallSetWindowAfterDestroy);
- if (doCallSetWindowAfterDestroy) {
- inst->Stop();
- inst->Destroy();
-
- if (window)
- window->CallSetWindow(nullinst);
- else
- inst->SetWindow(nsnull);
- }
- else {
- if (window)
- window->CallSetWindow(nullinst);
- else
- inst->SetWindow(nsnull);
-
- inst->Stop();
- inst->Destroy();
- }
+ nsCOMPtr<nsIPluginInstance> inst;
+ aInstanceOwner->GetInstance(*getter_AddRefs(inst));
+ if (inst) {
+ nsPluginWindow *win;
+ aInstanceOwner->GetWindow(win);
+ nsPluginNativeWindow *window = (nsPluginNativeWindow *)win;
+ nsCOMPtr<nsIPluginInstance> nullinst;
+
+ PRBool doCache = PR_TRUE;
+ PRBool doCallSetWindowAfterDestroy = PR_FALSE;
+
+ // first, determine if the plugin wants to be cached
+ inst->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *)&doCache);
+ if (!doCache) {
+ // then determine if the plugin wants Destroy to be called after
+ // Set Window. This is for bug 50547.
+ inst->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool,
+ (void *)&doCallSetWindowAfterDestroy);
+ if (doCallSetWindowAfterDestroy) {
+ inst->Stop();
+ inst->Destroy();
+
+ if (window)
+ window->CallSetWindow(nullinst);
+ else
+ inst->SetWindow(nsnull);
}
else {
if (window)
window->CallSetWindow(nullinst);
else
inst->SetWindow(nsnull);
inst->Stop();
+ inst->Destroy();
}
-
- nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(kCPluginManagerCID);
- if (pluginHost)
- pluginHost->StopPluginInstance(inst);
-
- // the frame is going away along with its widget
- // so tell the window to forget its widget too
- if (window)
- window->SetPluginWidget(nsnull);
+ }
+ else {
+ if (window)
+ window->CallSetWindow(nullinst);
+ else
+ inst->SetWindow(nsnull);
+
+ inst->Stop();
}
- mInstanceOwner->Destroy();
- NS_RELEASE(mInstanceOwner);
+ nsCOMPtr<nsIPluginHost> pluginHost = do_GetService(kCPluginManagerCID);
+ if (pluginHost)
+ pluginHost->StopPluginInstance(inst);
+
+ // the frame is going away along with its widget so tell the
+ // window to forget its widget too
+ if (window)
+ window->SetPluginWidget(nsnull);
}
+
+ aInstanceOwner->Destroy();
+}
+
+NS_IMETHODIMP
+nsStopPluginRunnable::Run()
+{
+ DoStopPlugin(mInstanceOwner);
+
+ return NS_OK;
+}
+
+void
+nsObjectFrame::StopPlugin()
+{
+ StopPluginInternal(PR_FALSE);
+}
+
+void
+nsObjectFrame::StopPluginInternal(PRBool aDelayedStop)
+{
+ if (mInstanceOwner == nsnull) {
+ return;
+ }
+
+ mInstanceOwner->PrepareToStop(aDelayedStop);
+
+#ifdef XP_WIN
+ // We only deal with delayed stopping of plugins on Win32 for now,
+ // as that's the only platform where we need to (AFAIK) and it's
+ // unclear how safe widget parenting is on other platforms.
+ if (aDelayedStop) {
+ // nsStopPluginRunnable will hold a strong reference to
+ // mInstanceOwner, and thus keep it alive as long as it needs it.
+ nsCOMPtr<nsIRunnable> evt = new nsStopPluginRunnable(mInstanceOwner);
+ NS_DispatchToCurrentThread(evt);
+
+ // If we're asked to do a delayed stop it means we're stopping the
+ // plugin because we're destroying the frame. In that case, tell
+ // the view to disown the widget (i.e. leave it up to us to
+ // destroy it).
+ nsIView *view = GetView();
+ if (view) {
+ view->DisownWidget();
+ }
+ } else
+#endif
+ {
+ DoStopPlugin(mInstanceOwner);
+ }
+
+ // Break relationship between frame and plugin instance owner
+ mInstanceOwner->SetOwner(nsnull);
+
+ NS_RELEASE(mInstanceOwner);
}
void
nsObjectFrame::NotifyContentObjectWrapper()
{
nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
if (!doc)
return;
@@ -1568,16 +1644,17 @@ nsPluginInstanceOwner::nsPluginInstanceO
mOwner = nsnull;
mTagText = nsnull;
mContentFocused = PR_FALSE;
mWidgetVisible = PR_TRUE;
mNumCachedAttrs = 0;
mNumCachedParams = 0;
mCachedAttrParamNames = nsnull;
mCachedAttrParamValues = nsnull;
+ mDestroyWidget = PR_FALSE;
}
nsPluginInstanceOwner::~nsPluginInstanceOwner()
{
PRInt32 cnt;
// shut off the timer.
if (mPluginTimer != nsnull) {
@@ -3126,30 +3203,65 @@ nsPluginInstanceOwner::Destroy()
// Unregister drag event listener;
target->RemoveEventListener(NS_LITERAL_STRING("dragdrop"), listener, PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("dragover"), listener, PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("dragexit"), listener, PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("dragenter"), listener, PR_TRUE);
target->RemoveEventListener(NS_LITERAL_STRING("draggesture"), listener, PR_TRUE);
}
+ if (mDestroyWidget && mWidget) {
+ mWidget->Destroy();
+ }
+
+ return NS_OK;
+}
+
+/*
+ * Prepare to stop
+ */
+void
+nsPluginInstanceOwner::PrepareToStop(PRBool aDelayedStop)
+{
+ if (!mWidget) {
+ return;
+ }
+
+#ifdef XP_WIN
+ if (aDelayedStop) {
+ // To delay stopping a plugin we need to reparent the plugin to
+ // the top-level Gecko widget so that we can safely tear down the
+ // plugin after its frame (and view) is gone.
+
+ nsIWidget *appTopWidget = mWidget->GetTopLevelWindow();
+
+ // Also hide and disable the widget to avoid it from appearing in
+ // odd places after reparenting it, but before it gets destroyed.
+ mWidget->Show(PR_FALSE);
+ mWidget->Enable(PR_FALSE);
+
+ // Reparent the plugins native window. This relies on the widget
+ // and plugin et al not holding any other references to its
+ // parent.
+ mWidget->SetParent(appTopWidget);
+
+ mDestroyWidget = PR_TRUE;
+ }
+#endif
+
// Unregister scroll position listener
nsIFrame* parentWithView = mOwner->GetAncestorWithView();
nsIView* curView = parentWithView ? parentWithView->GetView() : nsnull;
while (curView) {
nsIScrollableView* scrollingView = curView->ToScrollableView();
if (scrollingView)
scrollingView->RemoveScrollPositionListener((nsIScrollPositionListener *)this);
curView = curView->GetParent();
}
-
- mOwner = nsnull; // break relationship between frame and plugin instance owner
-
- return NS_OK;
}
// Paints are handled differently, so we just simulate an update event.
void nsPluginInstanceOwner::Paint(const nsRect& aDirtyRect, PRUint32 ndc)
{
if (!mInstance || !mOwner)
return;
--- a/layout/generic/nsObjectFrame.h
+++ b/layout/generic/nsObjectFrame.h
@@ -107,16 +107,24 @@ public:
virtual void Destroy();
NS_IMETHOD GetPluginInstance(nsIPluginInstance*& aPluginInstance);
virtual nsresult Instantiate(nsIChannel* aChannel, nsIStreamListener** aStreamListener);
virtual nsresult Instantiate(const char* aMimeType, nsIURI* aURI);
virtual void StopPlugin();
+ /*
+ * Stop a plugin instance. If aDelayedStop is true, the plugin will
+ * be stopped at a later point when it's safe to do so (i.e. not
+ * while destroying the frame tree). Delayed stopping is only
+ * implemented on Win32 for now.
+ */
+ void StopPluginInternal(PRBool aDelayedStop);
+
/* fail on any requests to get a cursor from us because plugins set their own! see bug 118877 */
NS_IMETHOD GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
// accessibility support
--- a/view/public/nsIView.h
+++ b/view/public/nsIView.h
@@ -294,16 +294,24 @@ public:
*/
nsIWidget* GetWidget() const { return mWindow; }
/**
* Returns PR_TRUE if the view has a widget associated with it.
*/
PRBool HasWidget() const { return mWindow != nsnull; }
+ /**
+ * If called, will make the view disown the widget and leave it up
+ * to other code to destroy it.
+ */
+ void DisownWidget() {
+ mWidgetDisowned = PR_TRUE;
+ }
+
#ifdef DEBUG
/**
* Output debug info to FILE
* @param out output file handle
* @param aIndent indentation depth
* NOTE: virtual so that debugging tools not linked into gklayout can access it
*/
virtual void List(FILE* out, PRInt32 aIndent = 0) const;
@@ -324,15 +332,16 @@ protected:
nsView *mFirstChild;
void *mClientData;
PRInt32 mZIndex;
nsViewVisibility mVis;
nscoord mPosX, mPosY;
nsRect mDimBounds; // relative to parent
float mOpacity;
PRUint32 mVFlags;
+ PRBool mWidgetDisowned;
virtual ~nsIView() {}
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIView, NS_IVIEW_IID)
#endif
--- a/view/src/nsView.cpp
+++ b/view/src/nsView.cpp
@@ -178,16 +178,17 @@ nsView::nsView(nsViewManager* aViewManag
mVis = aVisibility;
// Views should be transparent by default. Not being transparent is
// a promise that the view will paint all its pixels opaquely. Views
// should make this promise explicitly by calling
// SetViewContentTransparency.
mVFlags = 0;
mViewManager = aViewManager;
mDirtyRegion = nsnull;
+ mWidgetDisowned = PR_FALSE;
}
void nsView::DropMouseGrabbing() {
// check to see if we are grabbing events
if (mViewManager->GetMouseEventGrabber() == this) {
// we are grabbing events. Move the grab to the parent if we can.
PRBool boolResult; //not used
// if GetParent() returns null, then we release the grab, which is the best we can do
@@ -245,17 +246,19 @@ nsView::~nsView()
// Destroy and release the widget
if (mWindow)
{
// Release memory for the view wrapper
ViewWrapper* wrapper = GetWrapperFor(mWindow);
NS_IF_RELEASE(wrapper);
mWindow->SetClientData(nsnull);
- mWindow->Destroy();
+ if (!mWidgetDisowned) {
+ mWindow->Destroy();
+ }
NS_RELEASE(mWindow);
}
delete mDirtyRegion;
}
nsresult nsView::QueryInterface(const nsIID& aIID, void** aInstancePtr)
{
if (nsnull == aInstancePtr) {
--- a/widget/public/nsIWidget.h
+++ b/widget/public/nsIWidget.h
@@ -1048,16 +1048,22 @@ class nsIWidget : public nsISupports {
* Get a flag that controls native window animation.
* Ignored on any OS that doesn't support native animation.
*
* @param aAnimate Whether or not resizes are animated.
* @return NS_ERROR_NOT_IMPLEMENTED if not implemented on widget or platform
*/
NS_IMETHOD GetAnimatedResize(PRUint16* aAnimation) = 0;
+ /*
+ * Return the the nearest ancestor widget which does not have a
+ * Gecko parent.
+ */
+ virtual nsIWidget* GetTopLevelWindow(void) = 0;
+
protected:
// keep the list of children. We also keep track of our siblings.
// The ownership model is as follows: parent holds a strong ref to
// the first element of the list, and each element holds a strong
// ref to the next element in the list. The prevsibling and
// lastchild pointers are weak, which is fine as long as they are
// maintained properly.
nsCOMPtr<nsIWidget> mFirstChild;
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -7369,17 +7369,17 @@ PRBool nsWindow::OnIMEQueryCharPosition(
//==========================================================================
void
nsWindow::ResolveIMECaretPos(nsWindow* aClient,
nsRect& aEventResult,
nsRect& aResult)
{
// RootView coordinates -> Screen coordinates
- GetTopLevelWindow()->WidgetToScreen(aEventResult, aResult);
+ GetTopLevelWindowInternal()->WidgetToScreen(aEventResult, aResult);
// if aClient is nsnull, returns screen coordinates
if (!aClient)
return;
// screen coordinates -> client coordinates
aClient->ScreenToWidget(aResult, aResult);
}
//==========================================================================
@@ -7761,16 +7761,36 @@ nsWindow::GetLastInputEventTime(PRUint32
gLastInputEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
}
aTime = gLastInputEventTime;
return NS_OK;
}
+nsIWidget* nsWindow::GetTopLevelWindow(void)
+{
+ HWND hWnd = (HWND)GetNativeData(NS_NATIVE_WINDOW);
+ HWND rootWnd = hWnd;
+ nsIWidget *topWidget = nsnull;
+
+ while (1) {
+ HWND parent = ::GetParent(rootWnd);
+
+ if (!parent || GetNSWindowPtr(parent) == nsnull) {
+ break;
+ }
+
+ rootWnd = parent;
+ }
+
+ return GetNSWindowPtr(rootWnd);
+}
+
+
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//-- NOTE!!! These hook functions can be removed when we migrate to
//-- XBL-Form Controls
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//#define DISPLAY_NOISY_MSGF_MSG
@@ -8179,17 +8199,17 @@ STDMETHODIMP_(LRESULT) nsWindow::Lresult
}
return 0;
}
#endif
#ifdef MOZ_XUL
-nsWindow* nsWindow::GetTopLevelWindow()
+nsWindow* nsWindow::GetTopLevelWindowInternal()
{
nsWindow* curWindow = this;
while (PR_TRUE)
{
nsWindow* parentWindow = curWindow->GetParent(PR_TRUE);
if (parentWindow)
@@ -8298,31 +8318,31 @@ void nsWindow::ResizeTranslucentWindow(P
HGDIOBJ oldBitmap = ::SelectObject(mMemoryDC, mMemoryBitmap);
::DeleteObject(oldBitmap);
}
#endif
}
NS_IMETHODIMP nsWindow::GetWindowTranslucency(PRBool& aTranslucent)
{
- aTranslucent = GetTopLevelWindow()->GetWindowTranslucencyInner();
+ aTranslucent = GetTopLevelWindowInternal()->GetWindowTranslucencyInner();
return NS_OK;
}
NS_IMETHODIMP nsWindow::SetWindowTranslucency(PRBool aTranslucent)
{
- nsresult rv = GetTopLevelWindow()->SetWindowTranslucencyInner(aTranslucent);
+ nsresult rv = GetTopLevelWindowInternal()->SetWindowTranslucencyInner(aTranslucent);
return rv;
}
NS_IMETHODIMP nsWindow::UpdateTranslucentWindowAlpha(const nsRect& aRect, PRUint8* aAlphas)
{
- GetTopLevelWindow()->UpdateTranslucentWindowAlphaInner(aRect, aAlphas);
+ GetTopLevelWindowInternal()->UpdateTranslucentWindowAlphaInner(aRect, aAlphas);
return NS_OK;
}
nsresult nsWindow::SetWindowTranslucencyInner(PRBool aTranslucent)
{
if (aTranslucent == mIsTranslucent)
return NS_OK;
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -199,17 +199,19 @@ public:
virtual void SetUpForPaint(HDC aHDC);
virtual void ConvertToDeviceCoordinates(nscoord& aX,nscoord& aY) {}
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, PRBool aDoCapture, PRBool aConsumeRollupEvent);
NS_IMETHOD GetAttention(PRInt32 aCycleCount);
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime);
- nsWindow* GetTopLevelWindow();
+ virtual nsIWidget* GetTopLevelWindow(void);
+
+ nsWindow* GetTopLevelWindowInternal();
#ifdef MOZ_CAIRO_GFX
gfxASurface *GetThebesSurface();
#endif
#ifdef MOZ_XUL
NS_IMETHOD SetWindowTranslucency(PRBool aTransparent);
NS_IMETHOD GetWindowTranslucency(PRBool& aTransparent);
--- a/widget/src/xpwidgets/nsBaseWidget.cpp
+++ b/widget/src/xpwidgets/nsBaseWidget.cpp
@@ -851,16 +851,23 @@ nsBaseWidget::SetAnimatedResize(PRUint16
}
NS_IMETHODIMP
nsBaseWidget::GetAnimatedResize(PRUint16* aAnimation)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
+nsIWidget* nsBaseWidget::GetTopLevelWindow(void)
+{
+ NS_WARNING("Not implemented");
+
+ return nsnull;
+}
+
/**
* Modifies aFile to point at an icon file with the given name and suffix. The
* suffix may correspond to a file extension with leading '.' if appropriate.
* Returns true if the icon file exists and can be read.
*/
static PRBool
ResolveIconNameHelper(nsILocalFile *aFile,
const nsAString &aIconName,
--- a/widget/src/xpwidgets/nsBaseWidget.h
+++ b/widget/src/xpwidgets/nsBaseWidget.h
@@ -128,16 +128,17 @@ public:
NS_IMETHOD ScrollRect(nsRect &aRect, PRInt32 aDx, PRInt32 aDy);
NS_IMETHOD ScrollWidgets(PRInt32 aDx, PRInt32 aDy);
NS_IMETHOD EnableDragDrop(PRBool aEnable);
NS_IMETHOD GetAttention(PRInt32 aCycleCount);
NS_IMETHOD GetLastInputEventTime(PRUint32& aTime);
NS_IMETHOD SetIcon(const nsAString &anIconSpec);
NS_IMETHOD SetAnimatedResize(PRUint16 aAnimation);
NS_IMETHOD GetAnimatedResize(PRUint16* aAnimation);
+ virtual nsIWidget* GetTopLevelWindow();
virtual void ConvertToDeviceCoordinates(nscoord &aX,nscoord &aY) {}
virtual void FreeNativeData(void * data, PRUint32 aDataType) {}//~~~
protected:
virtual void ResolveIconName(const nsAString &aIconName,
const nsAString &aIconSuffix,
nsILocalFile **aResult);