From 4c402841b43dc2abd098c016e73dfd0caf7b710e Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Fri, 3 Feb 2006 21:28:11 +0000 Subject: [PATCH] Patch for bug 324642 "Add an API to expose the DOM node that the mouse is over when informing the WebBrowserChrome object to update the status bar." r=biesi sr=bzbarsky git-svn-id: svn://10.0.0.236/trunk@188880 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/docshell/base/nsWebShell.cpp | 311 +++++++++++------- .../embedding/browser/webBrowser/Makefile.in | 1 + .../webBrowser/nsIWebBrowserChrome2.idl | 65 ++++ .../appshell/public/nsIXULBrowserWindow.idl | 33 +- .../xpfe/appshell/src/nsContentTreeOwner.cpp | 53 ++- .../xpfe/appshell/src/nsContentTreeOwner.h | 9 +- 6 files changed, 312 insertions(+), 160 deletions(-) create mode 100644 mozilla/embedding/browser/webBrowser/nsIWebBrowserChrome2.idl diff --git a/mozilla/docshell/base/nsWebShell.cpp b/mozilla/docshell/base/nsWebShell.cpp index 1669032df94..06183dd8ce8 100644 --- a/mozilla/docshell/base/nsWebShell.cpp +++ b/mozilla/docshell/base/nsWebShell.cpp @@ -40,7 +40,7 @@ #include "nsDocShell.h" #include "nsWebShell.h" -#include "nsIWebBrowserChrome.h" +#include "nsIWebBrowserChrome2.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIWebProgress.h" @@ -161,19 +161,103 @@ IsOffline() //---------------------------------------------------------------------- +// Check prefs to see if pings are enabled +static PRBool +PingsEnabled() +{ + PRBool allow = PR_FALSE; + + nsCOMPtr prefs = + do_GetService(NS_PREFSERVICE_CONTRACTID); + if (prefs) { + PRBool val; + if (NS_SUCCEEDED(prefs->GetBoolPref("browser.send_pings", &val))) + allow = val; + } + + return allow; +} + +typedef void (* ForEachPingCallback)(void *closure, nsIContent *content, + nsIURI *uri, nsIIOService *ios); + +static void +ForEachPing(nsIContent *content, ForEachPingCallback callback, void *closure) +{ + // NOTE: Using nsIDOMNSHTMLAnchorElement2::GetPing isn't really worth it here + // since we'd still need to parse the resulting string. Instead, we + // just parse the raw attribute. It might be nice if the content node + // implemented an interface that exposed an enumeration of nsIURIs. + + // Make sure we are dealing with either an or element in the HTML + // or XHTML namespace. + if (!content->IsContentOfType(nsIContent::eHTML)) + return; + nsIAtom *nameAtom = content->Tag(); + if (!nameAtom->EqualsUTF8(NS_LITERAL_CSTRING("a")) && + !nameAtom->EqualsUTF8(NS_LITERAL_CSTRING("area"))) + return; + + nsCOMPtr pingAtom = do_GetAtom("ping"); + if (!pingAtom) + return; + + nsAutoString value; + content->GetAttr(kNameSpaceID_None, pingAtom, value); + if (value.IsEmpty()) + return; + + nsCOMPtr ios = do_GetIOService(); + if (!ios) + return; + + nsIDocument *doc = content->GetOwnerDoc(); + if (!doc) + return; + + // value contains relative URIs split on spaces (U+0020) + const PRUnichar *start = value.BeginReading(); + const PRUnichar *end = value.EndReading(); + const PRUnichar *iter = start; + for (;;) { + if (iter < end && *iter != ' ') { + ++iter; + } else { // iter is pointing at either end or a space + while (*start == ' ' && start < iter) + ++start; + if (iter != start) { + nsCOMPtr uri, baseURI = content->GetBaseURI(); + ios->NewURI(NS_ConvertUTF16toUTF8(Substring(start, iter)), + doc->GetDocumentCharacterSet().get(), + baseURI, getter_AddRefs(uri)); + if (uri) { + // Ignore non-HTTP(S) pings: + PRBool match; + if ((NS_SUCCEEDED(uri->SchemeIs("http", &match)) && match) || + (NS_SUCCEEDED(uri->SchemeIs("https", &match)) && match)) + callback(closure, content, uri, ios); + } + } + start = iter = iter + 1; + if (iter >= end) + break; + } + } +} + +//---------------------------------------------------------------------- + // We wait this many milliseconds before killing the ping channel... #define PING_TIMEOUT 10000 static void OnPingTimeout(nsITimer *timer, void *closure) { - nsIRequest *request = NS_STATIC_CAST(nsIRequest *, closure); - request->Cancel(NS_BINDING_ABORTED); - request->Release(); + nsILoadGroup *loadGroup = NS_STATIC_CAST(nsILoadGroup *, closure); + loadGroup->Cancel(NS_ERROR_ABORT); + loadGroup->Release(); } -//---------------------------------------------------------------------- - class nsPingListener : public nsIStreamListener { public: @@ -207,14 +291,16 @@ nsPingListener::OnStopRequest(nsIRequest *request, nsISupports *context, } static void -SendPing(const nsSubstring &relSpec, nsIDocument *doc, nsIURI *referrer, - nsIIOService *ios) +SendPing(void *closure, nsIContent *content, nsIURI *uri, nsIIOService *ios) { + nsIURI *referrer = NS_STATIC_CAST(nsIURI *, closure); + + nsIDocument *doc = content->GetOwnerDoc(); + if (!doc) + return; + nsCOMPtr chan; - ios->NewChannel(NS_ConvertUTF16toUTF8(relSpec), - doc->GetDocumentCharacterSet().get(), - doc->GetBaseURI(), - getter_AddRefs(chan)); + ios->NewChannelFromURI(uri, getter_AddRefs(chan)); if (!chan) return; @@ -222,124 +308,90 @@ SendPing(const nsSubstring &relSpec, nsIDocument *doc, nsIURI *referrer, chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING); nsCOMPtr httpChan = do_QueryInterface(chan); - if (httpChan) { - // This is needed in order for 3rd-party cookie blocking to work. - nsCOMPtr httpInternal = do_QueryInterface(httpChan); - if (httpInternal) - httpInternal->SetDocumentURI(doc->GetBaseURI()); + if (!httpChan) + return; - if (referrer) - httpChan->SetReferrer(referrer); + // This is needed in order for 3rd-party cookie blocking to work. + nsCOMPtr httpInternal = do_QueryInterface(httpChan); + if (httpInternal) + httpInternal->SetDocumentURI(doc->GetDocumentURI()); - httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST")); + if (referrer) + httpChan->SetReferrer(referrer); - // Remove extraneous request headers (to reduce request size) - httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"), - EmptyCString(), PR_FALSE); - httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"), - EmptyCString(), PR_FALSE); - httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-charset"), - EmptyCString(), PR_FALSE); - httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"), - EmptyCString(), PR_FALSE); + httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST")); - nsCOMPtr uploadChan = do_QueryInterface(httpChan); - if (!uploadChan) - return; + // Remove extraneous request headers (to reduce request size) + httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"), + EmptyCString(), PR_FALSE); + httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"), + EmptyCString(), PR_FALSE); + httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-charset"), + EmptyCString(), PR_FALSE); + httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"), + EmptyCString(), PR_FALSE); - // To avoid sending an unnecessary Content-Type header, we encode the - // closing portion of the headers in the POST body. - NS_NAMED_LITERAL_CSTRING(uploadData, "Content-Length: 0\r\n\r\n"); + nsCOMPtr uploadChan = do_QueryInterface(httpChan); + if (!uploadChan) + return; - nsCOMPtr uploadStream; - NS_NewPostDataStream(getter_AddRefs(uploadStream), PR_FALSE, - uploadData, 0); - if (!uploadStream) - return; + // To avoid sending an unnecessary Content-Type header, we encode the + // closing portion of the headers in the POST body. + NS_NAMED_LITERAL_CSTRING(uploadData, "Content-Length: 0\r\n\r\n"); - uploadChan->SetUploadStream(uploadStream, EmptyCString(), -1); - } + nsCOMPtr uploadStream; + NS_NewPostDataStream(getter_AddRefs(uploadStream), PR_FALSE, + uploadData, 0); + if (!uploadStream) + return; + + uploadChan->SetUploadStream(uploadStream, EmptyCString(), -1); + + // The channel needs to have a loadgroup associated with it, so that we can + // cancel the channel and any redirected channels it may create. + nsCOMPtr loadGroup = + do_CreateInstance(NS_LOADGROUP_CONTRACTID); + if (!loadGroup) + return; + chan->SetLoadGroup(loadGroup); // Construct a listener that merely discards any response. If successful at // opening the channel, then it is not necessary to hold a reference to the // channel. The networking subsystem will take care of that for us. nsCOMPtr listener = new nsPingListener(); - if (listener) { - chan->AsyncOpen(listener, nsnull); + if (!listener) + return; - // Prevent ping requests from stalling and never being garbage collected... - nsCOMPtr timer = - do_CreateInstance(NS_TIMER_CONTRACTID); - if (timer) { - nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, chan, - PING_TIMEOUT, - nsITimer::TYPE_ONE_SHOT); - if (NS_SUCCEEDED(rv)) { - // When the timer expires, the callback function will release this - // reference to the channel. - NS_STATIC_CAST(nsIChannel *, chan.get())->AddRef(); - } + chan->AsyncOpen(listener, nsnull); + + // Prevent ping requests from stalling and never being garbage collected... + nsCOMPtr timer = + do_CreateInstance(NS_TIMER_CONTRACTID); + if (timer) { + nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, loadGroup, + PING_TIMEOUT, + nsITimer::TYPE_ONE_SHOT); + if (NS_SUCCEEDED(rv)) { + // When the timer expires, the callback function will release this + // reference to the loadgroup. + NS_STATIC_CAST(nsILoadGroup *, loadGroup.get())->AddRef(); + loadGroup = 0; } } + + // If we failed to setup the timer, then we should just cancel the channel + // because we won't be able to ensure that it goes away in a timely manner. + if (loadGroup) + chan->Cancel(NS_ERROR_ABORT); } // Spec: http://whatwg.org/specs/web-apps/current-work/#ping static void DispatchPings(nsIContent *content, nsIURI *referrer) { - // Make sure we are dealing with either an or element in the HTML - // or XHTML namespace. - if (!content->IsContentOfType(nsIContent::eHTML)) + if (!PingsEnabled()) return; - nsIAtom *nameAtom = content->Tag(); - if (!nameAtom->EqualsUTF8(NS_LITERAL_CSTRING("a")) && - !nameAtom->EqualsUTF8(NS_LITERAL_CSTRING("area"))) - return; - - nsCOMPtr pingAtom = do_GetAtom("ping"); - if (!pingAtom) - return; - - nsAutoString value; - content->GetAttr(kNameSpaceID_None, pingAtom, value); - if (value.IsEmpty()) - return; - - // check prefs to see if pings are enabled - nsCOMPtr prefs = - do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - PRBool allow = PR_TRUE; - prefs->GetBoolPref("browser.send_pings", &allow); - if (!allow) - return; - } - - nsCOMPtr ios = do_GetIOService(); - if (!ios) - return; - - nsIDocument *doc = content->GetOwnerDoc(); - if (!doc) - return; - - // value contains relative URIs split on spaces (U+0020) - const PRUnichar *start = value.BeginReading(); - const PRUnichar *end = value.EndReading(); - const PRUnichar *iter = start; - for (;;) { - if (iter < end && *iter != ' ') { - ++iter; - } else { // iter is pointing at either end or a space - while (*start == ' ' && start < iter) - ++start; - if (iter != start) - SendPing(Substring(start, iter), doc, referrer, ios); - start = iter = iter + 1; - if (iter >= end) - break; - } - } + ForEachPing(content, SendPing, referrer); } //---------------------------------------------------------------------- @@ -755,27 +807,40 @@ nsWebShell::OnOverLink(nsIContent* aContent, nsIURI* aURI, const PRUnichar* aTargetSpec) { - nsCOMPtr browserChrome(do_GetInterface(mTreeOwner)); + nsCOMPtr browserChrome2 = do_GetInterface(mTreeOwner); nsresult rv = NS_ERROR_FAILURE; - if (browserChrome) { - nsCOMPtr textToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); - if (NS_FAILED(rv)) return rv; + nsCOMPtr browserChrome; + if (!browserChrome2) { + browserChrome = do_GetInterface(mTreeOwner); + if (!browserChrome) + return rv; + } - // use url origin charset to unescape the URL - nsCAutoString charset; - rv = aURI->GetOriginCharset(charset); - NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr textToSubURI = + do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); + if (NS_FAILED(rv)) + return rv; - nsCAutoString spec; - rv = aURI->GetSpec(spec); - NS_ENSURE_SUCCESS(rv, rv); + // use url origin charset to unescape the URL + nsCAutoString charset; + rv = aURI->GetOriginCharset(charset); + NS_ENSURE_SUCCESS(rv, rv); - nsAutoString uStr; - rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr); + nsCAutoString spec; + rv = aURI->GetSpec(spec); + NS_ENSURE_SUCCESS(rv, rv); - if (NS_SUCCEEDED(rv)) - rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get()); + nsAutoString uStr; + rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr); + NS_ENSURE_SUCCESS(rv, rv); + + if (browserChrome2) { + nsCOMPtr element = do_QueryInterface(aContent); + rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK, + uStr, element); + } else { + rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get()); } return rv; } diff --git a/mozilla/embedding/browser/webBrowser/Makefile.in b/mozilla/embedding/browser/webBrowser/Makefile.in index e982241923e..8bf63a12f19 100644 --- a/mozilla/embedding/browser/webBrowser/Makefile.in +++ b/mozilla/embedding/browser/webBrowser/Makefile.in @@ -97,6 +97,7 @@ XPIDLSRCS = \ nsICommandHandler.idl \ nsIEmbeddingSiteWindow2.idl \ nsIContextMenuListener2.idl \ + nsIWebBrowserChrome2.idl \ $(NULL) CPPSRCS = \ diff --git a/mozilla/embedding/browser/webBrowser/nsIWebBrowserChrome2.idl b/mozilla/embedding/browser/webBrowser/nsIWebBrowserChrome2.idl new file mode 100644 index 00000000000..d9746458f38 --- /dev/null +++ b/mozilla/embedding/browser/webBrowser/nsIWebBrowserChrome2.idl @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* ***** 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 mozilla.org code. + * + * The Initial Developer of the Original Code is Google Inc. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Darin Fisher + * + * 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 "nsIWebBrowserChrome.idl" + +/** + * nsIWebBrowserChrome2 is an extension to nsIWebBrowserChrome. + */ +[scriptable, uuid(2585a7b1-7b47-43c4-bf17-c6bf84e09b7b)] +interface nsIWebBrowserChrome2 : nsIWebBrowserChrome +{ + /** + * Called when the status text in the chrome needs to be updated. This + * method may be called instead of nsIWebBrowserChrome::SetStatus. An + * implementor of this method, should still implement SetStatus. + * + * @param statusType + * Indicates what is setting the text. + * @param status + * Status string. Null is an acceptable value meaning no status. + * @param contextNode + * An object that provides context pertaining to the status type. + * If statusType is STATUS_LINK, then statusContext may be a DOM + * node corresponding to the source of the link. This value can + * be null if there is no context. + */ + void setStatusWithContext(in unsigned long statusType, + in AString statusText, + in nsISupports statusContext); +}; diff --git a/mozilla/xpfe/appshell/public/nsIXULBrowserWindow.idl b/mozilla/xpfe/appshell/public/nsIXULBrowserWindow.idl index 3dd05808a76..841f0de5048 100644 --- a/mozilla/xpfe/appshell/public/nsIXULBrowserWindow.idl +++ b/mozilla/xpfe/appshell/public/nsIXULBrowserWindow.idl @@ -39,30 +39,31 @@ #include "nsISupports.idl" +interface nsIRequest; +interface nsIDOMElement; + /** * The nsIXULBrowserWindow supplies the methods that may be called from the * internals of the browser area to tell the containing xul window to update * it's ui. */ - -interface nsIRequest; - -[scriptable, uuid(46B4015C-0121-11d4-9877-00C04FA0D27A)] +[scriptable, uuid(67a601df-f091-4894-a2e2-2e6cfebb35ea)] interface nsIXULBrowserWindow : nsISupports { - /* - Sets the status according to JS' version of status. - */ - void setJSStatus(in wstring status); + /** + * Sets the status according to JS' version of status. + */ + void setJSStatus(in AString status); - /* - Sets the default status according to JS' version of default status. - */ - void setJSDefaultStatus(in wstring status); + /** + * Sets the default status according to JS' version of default status. + */ + void setJSDefaultStatus(in AString status); - /* - Tells the object implementing this function what link we are currently over. - */ - void setOverLink(in wstring link); + /** + * Tells the object implementing this function what link we are currently + * over. + */ + void setOverLink(in AString link, in nsIDOMElement element); }; diff --git a/mozilla/xpfe/appshell/src/nsContentTreeOwner.cpp b/mozilla/xpfe/appshell/src/nsContentTreeOwner.cpp index 8572d41df07..3249fac2222 100644 --- a/mozilla/xpfe/appshell/src/nsContentTreeOwner.cpp +++ b/mozilla/xpfe/appshell/src/nsContentTreeOwner.cpp @@ -114,6 +114,7 @@ NS_INTERFACE_MAP_BEGIN(nsContentTreeOwner) NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeOwner) NS_INTERFACE_MAP_ENTRY(nsIBaseWindow) NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome) + NS_INTERFACE_MAP_ENTRY(nsIWebBrowserChrome2) NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIEmbeddingSiteWindow, mSiteWindow2) NS_INTERFACE_MAP_ENTRY_AGGREGATED(nsIEmbeddingSiteWindow2, mSiteWindow2) @@ -357,10 +358,12 @@ nsContentTreeOwner::GetPersistence(PRBool* aPersistPosition, } //***************************************************************************** -// nsContentTreeOwner::nsIWebBrowserChrome +// nsContentTreeOwner::nsIWebBrowserChrome2 //***************************************************************************** -NS_IMETHODIMP nsContentTreeOwner::SetStatus(PRUint32 aStatusType, const PRUnichar* aStatus) +NS_IMETHODIMP nsContentTreeOwner::SetStatusWithContext(PRUint32 aStatusType, + const nsAString &aStatusText, + nsISupports *aStatusContext) { // We only allow the status to be set from the primary content shell if (!mPrimary) @@ -369,25 +372,41 @@ NS_IMETHODIMP nsContentTreeOwner::SetStatus(PRUint32 aStatusType, const PRUnicha nsCOMPtr xulBrowserWindow; mXULWindow->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow)); - if (xulBrowserWindow) - { - switch(aStatusType) - { - case STATUS_SCRIPT: - xulBrowserWindow->SetJSStatus(aStatus); - break; - case STATUS_SCRIPT_DEFAULT: - xulBrowserWindow->SetJSDefaultStatus(aStatus); - break; - case STATUS_LINK: - xulBrowserWindow->SetOverLink(aStatus); - break; - } - } + if (xulBrowserWindow) + { + switch(aStatusType) + { + case STATUS_SCRIPT: + xulBrowserWindow->SetJSStatus(aStatusText); + break; + case STATUS_SCRIPT_DEFAULT: + xulBrowserWindow->SetJSDefaultStatus(aStatusText); + break; + case STATUS_LINK: + { + nsCOMPtr element = do_QueryInterface(aStatusContext); + xulBrowserWindow->SetOverLink(aStatusText, element); + break; + } + } + } return NS_OK; } +//***************************************************************************** +// nsContentTreeOwner::nsIWebBrowserChrome +//***************************************************************************** + +NS_IMETHODIMP nsContentTreeOwner::SetStatus(PRUint32 aStatusType, + const PRUnichar* aStatus) +{ + return SetStatusWithContext(aStatusType, + aStatus ? nsDependentString(aStatus) + : EmptyString(), + nsnull); +} + NS_IMETHODIMP nsContentTreeOwner::SetWebBrowser(nsIWebBrowser* aWebBrowser) { NS_ERROR("Haven't Implemented this yet"); diff --git a/mozilla/xpfe/appshell/src/nsContentTreeOwner.h b/mozilla/xpfe/appshell/src/nsContentTreeOwner.h index b0623262514..771bbc0d871 100644 --- a/mozilla/xpfe/appshell/src/nsContentTreeOwner.h +++ b/mozilla/xpfe/appshell/src/nsContentTreeOwner.h @@ -49,15 +49,15 @@ #include "nsIDocShellTreeOwner.h" #include "nsIInterfaceRequestor.h" #include "nsIInterfaceRequestorUtils.h" -#include "nsIWebBrowserChrome.h" +#include "nsIWebBrowserChrome2.h" class nsXULWindow; class nsSiteWindow2; class nsContentTreeOwner : public nsIDocShellTreeOwner, - public nsIBaseWindow, - public nsIInterfaceRequestor, - public nsIWebBrowserChrome + public nsIBaseWindow, + public nsIInterfaceRequestor, + public nsIWebBrowserChrome2 { friend class nsXULWindow; friend class nsSiteWindow2; @@ -69,6 +69,7 @@ public: NS_DECL_NSIDOCSHELLTREEOWNER NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSIWEBBROWSERCHROME + NS_DECL_NSIWEBBROWSERCHROME2 protected: nsContentTreeOwner(PRBool fPrimary);