2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2000-03-21 16:14:34 +03:00
|
|
|
|
2013-12-09 06:52:54 +04:00
|
|
|
#include "mozilla/ArrayUtils.h"
|
2018-03-22 21:20:41 +03:00
|
|
|
#include "mozilla/ComputedStyle.h"
|
2011-10-11 09:50:08 +04:00
|
|
|
|
2000-01-12 12:25:28 +03:00
|
|
|
#include "nsCOMPtr.h"
|
2001-06-22 02:02:47 +04:00
|
|
|
#include "nsNetUtil.h"
|
2000-05-28 08:10:50 +04:00
|
|
|
#include "nsXBLService.h"
|
2000-09-22 09:02:20 +04:00
|
|
|
#include "nsXBLWindowKeyHandler.h"
|
2000-01-12 12:44:18 +03:00
|
|
|
#include "nsIInputStream.h"
|
2014-02-28 03:04:46 +04:00
|
|
|
#include "nsNameSpaceManager.h"
|
2000-01-12 12:44:18 +03:00
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsIURL.h"
|
|
|
|
#include "nsIChannel.h"
|
2017-08-17 08:29:03 +03:00
|
|
|
#include "nsString.h"
|
2000-01-12 12:44:18 +03:00
|
|
|
#include "plstr.h"
|
2000-01-12 12:57:45 +03:00
|
|
|
#include "nsIContent.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2000-01-12 13:20:11 +03:00
|
|
|
#include "nsIXMLContentSink.h"
|
2001-02-19 15:55:42 +03:00
|
|
|
#include "nsContentCID.h"
|
2013-03-20 20:22:26 +04:00
|
|
|
#include "mozilla/dom/XMLDocument.h"
|
2006-12-26 20:47:52 +03:00
|
|
|
#include "nsGkAtoms.h"
|
2000-09-20 09:44:19 +04:00
|
|
|
#include "nsIObserverService.h"
|
2001-11-02 04:53:13 +03:00
|
|
|
#include "nsXBLContentSink.h"
|
2005-02-26 01:07:01 +03:00
|
|
|
#include "nsXBLBinding.h"
|
2003-03-07 02:59:18 +03:00
|
|
|
#include "nsXBLPrototypeBinding.h"
|
2010-07-15 05:53:11 +04:00
|
|
|
#include "nsXBLDocumentInfo.h"
|
2002-05-15 22:55:21 +04:00
|
|
|
#include "nsCRT.h"
|
2002-10-09 11:03:15 +04:00
|
|
|
#include "nsContentUtils.h"
|
2006-06-16 00:30:44 +04:00
|
|
|
#include "nsSyncLoadService.h"
|
2005-05-11 01:07:00 +04:00
|
|
|
#include "nsContentPolicyUtils.h"
|
2009-03-20 11:15:35 +03:00
|
|
|
#include "nsTArray.h"
|
2012-07-27 18:03:27 +04:00
|
|
|
#include "nsError.h"
|
2000-08-12 10:28:02 +04:00
|
|
|
|
2000-08-14 08:04:18 +04:00
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsIDocumentObserver.h"
|
2004-02-24 00:29:06 +03:00
|
|
|
#include "nsFrameManager.h"
|
2003-05-01 06:41:45 +04:00
|
|
|
#include "nsIScriptSecurityManager.h"
|
2006-10-08 14:18:41 +04:00
|
|
|
#include "nsIScriptError.h"
|
2011-11-04 00:39:08 +04:00
|
|
|
#include "nsXBLSerialize.h"
|
2000-08-14 08:04:18 +04:00
|
|
|
|
2003-04-11 04:56:27 +04:00
|
|
|
#ifdef MOZ_XUL
|
2007-03-12 08:53:33 +03:00
|
|
|
# include "nsXULPrototypeCache.h"
|
2003-04-11 04:56:27 +04:00
|
|
|
#endif
|
2011-06-25 03:12:34 +04:00
|
|
|
#include "nsIDOMEventListener.h"
|
2014-03-05 04:37:43 +04:00
|
|
|
#include "mozilla/Attributes.h"
|
2014-03-17 10:56:53 +04:00
|
|
|
#include "mozilla/EventListenerManager.h"
|
2011-05-29 03:42:57 +04:00
|
|
|
#include "mozilla/Preferences.h"
|
2016-12-14 06:11:28 +03:00
|
|
|
#include "mozilla/ServoStyleSet.h"
|
2018-04-05 22:12:37 +03:00
|
|
|
#include "mozilla/RestyleManager.h"
|
2017-11-24 17:15:38 +03:00
|
|
|
#include "mozilla/dom/ChildIterator.h"
|
2014-03-05 04:37:43 +04:00
|
|
|
#include "mozilla/dom/Event.h"
|
2011-07-20 23:18:54 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2011-05-29 03:42:57 +04:00
|
|
|
|
|
|
|
using namespace mozilla;
|
2013-04-06 04:44:15 +04:00
|
|
|
using namespace mozilla::dom;
|
2000-08-06 02:33:29 +04:00
|
|
|
|
2007-04-01 16:19:44 +04:00
|
|
|
#define NS_MAX_XBL_BINDING_RECURSION 20
|
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
nsXBLService* nsXBLService::gInstance = nullptr;
|
2012-05-23 22:46:04 +04:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
static bool IsAncestorBinding(Document* aDocument, nsIURI* aChildBindingURI,
|
2006-10-08 14:18:41 +04:00
|
|
|
nsIContent* aChild) {
|
|
|
|
NS_ASSERTION(aDocument, "expected a document");
|
|
|
|
NS_ASSERTION(aChildBindingURI, "expected a binding URI");
|
|
|
|
NS_ASSERTION(aChild, "expected a child content");
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t bindingRecursion = 0;
|
2008-07-23 08:50:20 +04:00
|
|
|
for (nsIContent* bindingParent = aChild->GetBindingParent(); bindingParent;
|
|
|
|
bindingParent = bindingParent->GetBindingParent()) {
|
2013-07-17 20:05:03 +04:00
|
|
|
nsXBLBinding* binding = bindingParent->GetXBLBinding();
|
2006-10-08 14:18:41 +04:00
|
|
|
if (!binding) {
|
|
|
|
continue;
|
|
|
|
}
|
2008-09-22 03:40:02 +04:00
|
|
|
|
2009-11-04 00:45:10 +03:00
|
|
|
if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) {
|
2007-04-01 16:19:44 +04:00
|
|
|
++bindingRecursion;
|
|
|
|
if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-08-26 09:02:31 +03:00
|
|
|
NS_ConvertUTF8toUTF16 bindingURI(aChildBindingURI->GetSpecOrDefault());
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t* params[] = {bindingURI.get()};
|
2011-12-15 18:47:03 +04:00
|
|
|
nsContentUtils::ReportToConsole(
|
2013-08-21 23:28:26 +04:00
|
|
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XBL"), aDocument,
|
2011-12-15 18:47:03 +04:00
|
|
|
nsContentUtils::eXBL_PROPERTIES, "TooDeepBindingRecursion", params,
|
|
|
|
ArrayLength(params));
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2006-10-08 14:18:41 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2006-10-08 14:18:41 +04:00
|
|
|
}
|
|
|
|
|
2000-08-06 02:33:29 +04:00
|
|
|
// Individual binding requests.
|
2001-04-04 09:00:08 +04:00
|
|
|
class nsXBLBindingRequest {
|
|
|
|
public:
|
2007-02-24 19:27:51 +03:00
|
|
|
nsCOMPtr<nsIURI> mBindingURI;
|
2000-08-06 08:57:55 +04:00
|
|
|
nsCOMPtr<nsIContent> mBoundElement;
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
void DocumentLoaded(Document* aBindingDoc) {
|
2004-12-02 05:24:28 +03:00
|
|
|
// We only need the document here to cause frame construction, so
|
|
|
|
// we need the current doc, not the owner doc.
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = mBoundElement->GetUncomposedDoc();
|
2000-08-06 08:57:55 +04:00
|
|
|
if (!doc) return;
|
|
|
|
|
2017-07-20 03:27:51 +03:00
|
|
|
// Get the binding.
|
|
|
|
bool ready = false;
|
|
|
|
nsXBLService::GetInstance()->BindingReady(mBoundElement, mBindingURI,
|
|
|
|
&ready);
|
|
|
|
if (!ready) return;
|
|
|
|
|
|
|
|
// Destroy the frames for mBoundElement. Do this after getting the binding,
|
|
|
|
// since if the binding fetch fails then we don't want to destroy the
|
|
|
|
// frames.
|
Bug 1389743: Only reconstruct frames synchronously from ContentRemoved when called from frame construction. r=mats
There's only one case of sync frame construction from ContentRemoved now, and
it's not on the element being removed, but on the whitespace siblings if needed,
and _only_ when they don't support lazy frame construction.
Basically, this switches all the RecreateFramesForContent calls to use
`aAsyncInsert` (which I changed to an enum class for readability), except when
we're already reframing.
Also, it switches ReframeTextIfNeeded to opt-in into lazy frame construction,
since it's used only when aFlags == CONTENT_REMOVED.
This allows to simplify the DestroyFramesFor API (which I'm happy to rename to
something more meaningful, since now it's something like
DestroyFramesForAndRecreateThemAsync), and do some other consistency cleanups.
A bunch of the ContentRemoved callsites were pretty random at passing
aAsyncInsert, and that was some kind of a mess. This patch ensures consistency,
and makes it impossible to do O(n^2) work when removing DOM nodes, which is
nice.
The underlying reason for this is explained in the description of bug 1377848,
and basically allows us to remove a bunch of Servo hacks on the longer term (a
few of them are going away already, yay!).
MozReview-Commit-ID: 2DrUTxGV8RX
--HG--
extra : rebase_source : f428d839a5482477dea22c0fea600d54f3e8799c
2017-08-23 10:58:57 +03:00
|
|
|
if (nsIPresShell* shell = doc->GetShell()) {
|
2017-10-26 00:12:25 +03:00
|
|
|
shell->DestroyFramesForAndRestyle(mBoundElement->AsElement());
|
2014-10-23 17:19:26 +04:00
|
|
|
}
|
|
|
|
MOZ_ASSERT(!mBoundElement->GetPrimaryFrame());
|
2000-08-06 08:57:55 +04:00
|
|
|
}
|
|
|
|
|
2007-02-24 19:27:51 +03:00
|
|
|
nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
|
2003-11-18 00:03:32 +03:00
|
|
|
: mBindingURI(aURI), mBoundElement(aBoundElement) {}
|
2000-08-14 08:04:18 +04:00
|
|
|
};
|
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
// nsXBLStreamListener, a helper class used for
|
2000-08-04 12:45:29 +04:00
|
|
|
// asynchronous parsing of URLs
|
|
|
|
/* Header file */
|
2015-03-21 19:28:04 +03:00
|
|
|
class nsXBLStreamListener final : public nsIStreamListener,
|
2015-03-27 21:52:19 +03:00
|
|
|
public nsIDOMEventListener {
|
2000-08-04 12:45:29 +04:00
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSISTREAMLISTENER
|
2001-04-10 10:01:08 +04:00
|
|
|
NS_DECL_NSIREQUESTOBSERVER
|
2011-06-25 03:12:34 +04:00
|
|
|
NS_DECL_NSIDOMEVENTLISTENER
|
2000-08-12 10:28:02 +04:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
nsXBLStreamListener(Document* aBoundDocument, nsIXMLContentSink* aSink,
|
|
|
|
Document* aBindingDocument);
|
2007-11-08 03:05:03 +03:00
|
|
|
|
2007-04-23 18:21:53 +04:00
|
|
|
void AddRequest(nsXBLBindingRequest* aRequest) {
|
|
|
|
mBindingRequests.AppendElement(aRequest);
|
|
|
|
}
|
2011-09-29 10:19:26 +04:00
|
|
|
bool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
|
2000-08-06 02:33:29 +04:00
|
|
|
|
2000-08-06 08:57:55 +04:00
|
|
|
private:
|
2014-06-23 23:56:07 +04:00
|
|
|
~nsXBLStreamListener();
|
|
|
|
|
2000-08-06 08:57:55 +04:00
|
|
|
nsCOMPtr<nsIStreamListener> mInner;
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsXBLBindingRequest*, 8> mBindingRequests;
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2018-10-31 23:39:03 +03:00
|
|
|
nsWeakPtr mBoundDocument;
|
2009-01-14 14:24:26 +03:00
|
|
|
nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> mBindingDocument; // Only set until OnStartRequest
|
2000-08-04 12:45:29 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Implementation file */
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsXBLStreamListener, nsIStreamListener, nsIRequestObserver,
|
|
|
|
nsIDOMEventListener)
|
2000-08-04 12:45:29 +04:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
nsXBLStreamListener::nsXBLStreamListener(Document* aBoundDocument,
|
2009-01-14 14:24:26 +03:00
|
|
|
nsIXMLContentSink* aSink,
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* aBindingDocument)
|
2009-01-14 14:24:26 +03:00
|
|
|
: mSink(aSink), mBindingDocument(aBindingDocument) {
|
2000-08-04 12:45:29 +04:00
|
|
|
/* member initializers and constructor code */
|
2009-01-14 14:24:26 +03:00
|
|
|
mBoundDocument = do_GetWeakReference(aBoundDocument);
|
2007-11-08 03:05:03 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
nsXBLStreamListener::~nsXBLStreamListener() {
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < mBindingRequests.Length(); i++) {
|
2009-03-20 11:15:35 +03:00
|
|
|
nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
|
2013-03-05 16:37:47 +04:00
|
|
|
delete req;
|
2007-11-08 03:05:03 +03:00
|
|
|
}
|
2000-08-04 12:45:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-02-28 02:42:27 +03:00
|
|
|
nsXBLStreamListener::OnDataAvailable(nsIRequest* request,
|
2013-03-05 16:37:47 +04:00
|
|
|
nsIInputStream* aInStr,
|
2012-09-06 06:41:02 +04:00
|
|
|
uint64_t aSourceOffset, uint32_t aCount) {
|
2000-08-04 12:45:29 +04:00
|
|
|
if (mInner)
|
2019-03-13 12:19:06 +03:00
|
|
|
return mInner->OnDataAvailable(request, aInStr, aSourceOffset, aCount);
|
2000-08-04 12:45:29 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2019-02-28 02:41:04 +03:00
|
|
|
nsXBLStreamListener::OnStartRequest(nsIRequest* request) {
|
2009-01-14 14:24:26 +03:00
|
|
|
// Make sure we don't hold on to the sink and binding document past this point
|
|
|
|
nsCOMPtr<nsIXMLContentSink> sink;
|
|
|
|
mSink.swap(sink);
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc;
|
2009-01-14 14:24:26 +03:00
|
|
|
mBindingDocument.swap(doc);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
|
|
|
|
NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
nsCOMPtr<nsILoadGroup> group;
|
|
|
|
request->GetLoadGroup(getter_AddRefs(group));
|
|
|
|
|
|
|
|
nsresult rv =
|
|
|
|
doc->StartDocumentLoad("loadAsInteractiveData", channel, group, nullptr,
|
|
|
|
getter_AddRefs(mInner), true, sink);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Make sure to add ourselves as a listener after StartDocumentLoad,
|
|
|
|
// since that resets the event listners on the document.
|
2013-04-06 04:44:15 +04:00
|
|
|
doc->AddEventListener(NS_LITERAL_STRING("load"), this, false);
|
|
|
|
|
2019-02-28 02:41:04 +03:00
|
|
|
return mInner->OnStartRequest(request);
|
2000-08-04 12:45:29 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
NS_IMETHODIMP
|
2019-03-13 12:19:06 +03:00
|
|
|
nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsresult aStatus) {
|
2000-08-12 10:28:02 +04:00
|
|
|
nsresult rv = NS_OK;
|
2000-08-06 08:57:55 +04:00
|
|
|
if (mInner) {
|
2019-02-28 02:41:31 +03:00
|
|
|
rv = mInner->OnStopRequest(request, aStatus);
|
2000-08-12 10:28:02 +04:00
|
|
|
}
|
2000-08-06 08:57:55 +04:00
|
|
|
|
2007-11-08 03:05:03 +03:00
|
|
|
// Don't hold onto the inner listener; holding onto it can create a cycle
|
|
|
|
// with the document
|
2012-07-30 18:20:58 +04:00
|
|
|
mInner = nullptr;
|
2000-08-06 08:57:55 +04:00
|
|
|
|
2000-08-12 10:28:02 +04:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2003-11-18 00:03:32 +03:00
|
|
|
bool nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt) {
|
2000-08-14 08:04:18 +04:00
|
|
|
// XXX Could be more efficient.
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t count = mBindingRequests.Length();
|
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2009-03-20 11:15:35 +03:00
|
|
|
nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
|
2011-09-29 10:19:26 +04:00
|
|
|
bool eq;
|
2003-11-18 00:03:32 +03:00
|
|
|
if (req->mBoundElement == aElt &&
|
2007-02-24 19:27:51 +03:00
|
|
|
NS_SUCCEEDED(req->mBindingURI->Equals(aURI, &eq)) && eq)
|
2011-10-17 18:59:28 +04:00
|
|
|
return true;
|
2000-08-14 08:04:18 +04:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
return false;
|
2000-08-14 08:04:18 +04:00
|
|
|
}
|
|
|
|
|
2018-04-20 07:49:29 +03:00
|
|
|
nsresult nsXBLStreamListener::HandleEvent(Event* aEvent) {
|
2000-08-12 10:28:02 +04:00
|
|
|
nsresult rv = NS_OK;
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t i;
|
|
|
|
uint32_t count = mBindingRequests.Length();
|
2007-11-08 03:05:03 +03:00
|
|
|
|
|
|
|
// Get the binding document; note that we don't hold onto it in this object
|
|
|
|
// to avoid creating a cycle
|
2018-04-20 07:49:29 +03:00
|
|
|
EventTarget* target = aEvent->GetCurrentTarget();
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> bindingDocument = do_QueryInterface(target);
|
2007-11-08 03:05:03 +03:00
|
|
|
NS_ASSERTION(bindingDocument, "Event not targeted at document?!");
|
|
|
|
|
2000-08-16 01:00:52 +04:00
|
|
|
// See if we're still alive.
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc(do_QueryReferent(mBoundDocument));
|
2000-08-16 01:00:52 +04:00
|
|
|
if (!doc) {
|
2000-10-29 02:17:53 +04:00
|
|
|
NS_WARNING(
|
|
|
|
"XBL load did not complete until after document went away! Modal "
|
|
|
|
"dialog bug?\n");
|
2000-08-16 01:00:52 +04:00
|
|
|
} else {
|
2001-03-04 01:01:01 +03:00
|
|
|
// We have to do a flush prior to notification of the document load.
|
|
|
|
// This has to happen since the HTML content sink can be holding on
|
|
|
|
// to notifications related to our children (e.g., if you bind to the
|
2014-03-19 01:25:39 +04:00
|
|
|
// <body> tag) that result in duplication of content.
|
2001-03-04 01:01:01 +03:00
|
|
|
// We need to get the sink's notifications flushed and then make the binding
|
|
|
|
// ready.
|
|
|
|
if (count > 0) {
|
2009-03-20 11:15:35 +03:00
|
|
|
nsXBLBindingRequest* req = mBindingRequests.ElementAt(0);
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* document = req->mBoundElement->GetUncomposedDoc();
|
2001-03-04 01:01:01 +03:00
|
|
|
if (document)
|
2017-01-05 10:31:56 +03:00
|
|
|
document->FlushPendingNotifications(FlushType::ContentAndNotify);
|
2001-03-04 01:01:01 +03:00
|
|
|
}
|
|
|
|
|
2000-08-16 01:00:52 +04:00
|
|
|
// Remove ourselves from the set of pending docs.
|
2007-02-17 02:02:08 +03:00
|
|
|
nsBindingManager* bindingManager = doc->BindingManager();
|
2007-11-08 03:05:03 +03:00
|
|
|
nsIURI* documentURI = bindingDocument->GetDocumentURI();
|
2003-11-18 00:03:32 +03:00
|
|
|
bindingManager->RemoveLoadingDocListener(documentURI);
|
2000-08-16 01:00:52 +04:00
|
|
|
|
2010-04-30 17:12:05 +04:00
|
|
|
if (!bindingDocument->GetRootElement()) {
|
2010-05-05 08:28:19 +04:00
|
|
|
// FIXME: How about an error console warning?
|
2012-04-09 05:37:41 +04:00
|
|
|
NS_WARNING(
|
|
|
|
"XBL doc with no root element - this usually shouldn't happen");
|
2000-09-02 05:09:47 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2000-08-16 01:00:52 +04:00
|
|
|
|
2001-11-02 04:53:13 +03:00
|
|
|
// Put our doc info in the doc table.
|
2007-11-08 03:05:03 +03:00
|
|
|
nsBindingManager* xblDocBindingManager = bindingDocument->BindingManager();
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsXBLDocumentInfo> info =
|
2007-02-27 03:14:01 +03:00
|
|
|
xblDocBindingManager->GetXBLDocumentInfo(documentURI);
|
2001-11-02 04:53:13 +03:00
|
|
|
xblDocBindingManager->RemoveXBLDocumentInfo(
|
|
|
|
info); // Break the self-imposed cycle.
|
2001-11-11 04:15:22 +03:00
|
|
|
if (!info) {
|
2011-11-04 00:39:07 +04:00
|
|
|
if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
|
2010-05-05 08:28:19 +04:00
|
|
|
NS_WARNING(
|
|
|
|
"An XBL file is malformed. Did you forget the XBL namespace on the "
|
|
|
|
"bindings tag?");
|
|
|
|
}
|
2011-12-15 18:47:03 +04:00
|
|
|
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
2013-08-21 23:28:26 +04:00
|
|
|
NS_LITERAL_CSTRING("XBL"), nullptr,
|
2011-12-15 18:47:03 +04:00
|
|
|
nsContentUtils::eXBL_PROPERTIES,
|
2012-07-30 18:20:58 +04:00
|
|
|
"MalformedXBL", nullptr, 0, documentURI);
|
2001-11-11 04:15:22 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2001-11-02 04:53:13 +03:00
|
|
|
|
2000-08-16 01:00:52 +04:00
|
|
|
// If the doc is a chrome URI, then we put it into the XUL cache.
|
2003-04-11 04:56:27 +04:00
|
|
|
#ifdef MOZ_XUL
|
2011-11-04 00:39:07 +04:00
|
|
|
if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
|
2007-03-12 08:53:33 +03:00
|
|
|
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
|
|
|
if (cache && cache->IsEnabled()) cache->PutXBLDocumentInfo(info);
|
2000-08-12 10:28:02 +04:00
|
|
|
}
|
2003-04-11 04:56:27 +04:00
|
|
|
#endif
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2003-06-21 03:33:43 +04:00
|
|
|
bindingManager->PutXBLDocumentInfo(info);
|
2000-08-12 10:28:02 +04:00
|
|
|
|
2000-08-16 01:00:52 +04:00
|
|
|
// Notify all pending requests that their bindings are
|
|
|
|
// ready and can be installed.
|
|
|
|
for (i = 0; i < count; i++) {
|
2009-03-20 11:15:35 +03:00
|
|
|
nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
|
2007-11-08 03:05:03 +03:00
|
|
|
req->DocumentLoaded(bindingDocument);
|
2000-08-16 01:00:52 +04:00
|
|
|
}
|
2000-08-12 10:28:02 +04:00
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
|
2000-08-12 10:28:02 +04:00
|
|
|
|
|
|
|
return rv;
|
2000-08-04 12:45:29 +04:00
|
|
|
}
|
|
|
|
|
2018-11-28 03:54:56 +03:00
|
|
|
// Implementation //////////////////////////////////////////////////////////////
|
2000-01-12 12:44:18 +03:00
|
|
|
|
|
|
|
// Implement our nsISupports methods
|
2014-04-27 11:06:00 +04:00
|
|
|
NS_IMPL_ISUPPORTS(nsXBLService, nsISupportsWeakReference)
|
2012-05-23 22:46:04 +04:00
|
|
|
|
|
|
|
void nsXBLService::Init() {
|
|
|
|
gInstance = new nsXBLService();
|
|
|
|
NS_ADDREF(gInstance);
|
|
|
|
}
|
2000-01-12 12:25:28 +03:00
|
|
|
|
2000-01-12 12:44:18 +03:00
|
|
|
// Constructors/Destructors
|
|
|
|
nsXBLService::nsXBLService(void) {}
|
|
|
|
|
|
|
|
nsXBLService::~nsXBLService(void) {}
|
2000-01-12 12:32:29 +03:00
|
|
|
|
2011-11-04 00:39:07 +04:00
|
|
|
// static
|
|
|
|
bool nsXBLService::IsChromeOrResourceURI(nsIURI* aURI) {
|
|
|
|
bool isChrome = false;
|
|
|
|
bool isResource = false;
|
2014-03-19 01:25:39 +04:00
|
|
|
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) &&
|
2011-11-04 00:39:07 +04:00
|
|
|
NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
|
|
|
|
return (isChrome || isResource);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-11-24 17:15:38 +03:00
|
|
|
// Servo avoids wasting work styling subtrees of elements with XBL bindings by
|
|
|
|
// default, so whenever we leave LoadBindings in a way that doesn't guarantee
|
|
|
|
// that the subtree is styled we need to take care of doing it manually.
|
|
|
|
static void EnsureSubtreeStyled(Element* aElement) {
|
2018-03-25 20:42:10 +03:00
|
|
|
if (!aElement->HasServoData()) {
|
2017-11-24 17:15:38 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Servo_Element_IsDisplayNone(aElement)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIPresShell* presShell = aElement->OwnerDoc()->GetShell();
|
|
|
|
if (!presShell || !presShell->DidInitialize()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-29 14:15:46 +03:00
|
|
|
ServoStyleSet* servoSet = presShell->StyleSet();
|
2017-11-24 17:15:38 +03:00
|
|
|
StyleChildrenIterator iter(aElement);
|
|
|
|
for (nsIContent* child = iter.GetNextChild(); child;
|
|
|
|
child = iter.GetNextChild()) {
|
2018-05-30 17:56:24 +03:00
|
|
|
Element* element = Element::FromNode(child);
|
|
|
|
if (!element) {
|
2017-11-24 17:15:38 +03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-05-30 17:56:24 +03:00
|
|
|
if (element->HasServoData()) {
|
2017-11-24 17:15:38 +03:00
|
|
|
// If any child was styled, all of them should be styled already, so we
|
|
|
|
// can bail out.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-30 17:56:24 +03:00
|
|
|
servoSet->StyleNewSubtree(element);
|
2017-11-24 17:15:38 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensures that EnsureSubtreeStyled is called on the element on destruction.
|
|
|
|
class MOZ_RAII AutoEnsureSubtreeStyled {
|
|
|
|
public:
|
|
|
|
explicit AutoEnsureSubtreeStyled(Element* aElement) : mElement(aElement) {}
|
|
|
|
|
|
|
|
~AutoEnsureSubtreeStyled() { EnsureSubtreeStyled(mElement); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Element* mElement;
|
|
|
|
};
|
|
|
|
|
2017-11-17 23:13:48 +03:00
|
|
|
// RAII class to restyle the XBL bound element when it shuffles the flat tree.
|
2017-11-24 17:15:38 +03:00
|
|
|
class MOZ_RAII AutoStyleElement {
|
2016-12-14 06:11:28 +03:00
|
|
|
public:
|
2017-12-04 04:47:54 +03:00
|
|
|
AutoStyleElement(Element* aElement, bool* aResolveStyle)
|
2017-11-17 22:52:29 +03:00
|
|
|
: mElement(aElement),
|
|
|
|
mHadData(aElement->HasServoData()),
|
2017-12-04 04:47:54 +03:00
|
|
|
mResolveStyle(aResolveStyle) {
|
|
|
|
MOZ_ASSERT(mResolveStyle);
|
2017-11-17 22:52:29 +03:00
|
|
|
if (mHadData) {
|
2018-04-05 22:12:37 +03:00
|
|
|
RestyleManager::ClearServoDataFromSubtree(
|
|
|
|
mElement, RestyleManager::IncludeRoot::No);
|
2017-11-17 22:52:29 +03:00
|
|
|
}
|
|
|
|
}
|
2017-12-04 04:47:54 +03:00
|
|
|
|
2017-11-17 22:52:29 +03:00
|
|
|
~AutoStyleElement() {
|
2016-12-14 06:11:28 +03:00
|
|
|
nsIPresShell* presShell = mElement->OwnerDoc()->GetShell();
|
2017-11-17 22:52:29 +03:00
|
|
|
if (!mHadData || !presShell || !presShell->DidInitialize()) {
|
2017-03-20 12:08:15 +03:00
|
|
|
return;
|
|
|
|
}
|
2017-07-26 20:43:48 +03:00
|
|
|
|
2017-12-04 04:47:54 +03:00
|
|
|
if (*mResolveStyle) {
|
|
|
|
mElement->ClearServoData();
|
|
|
|
|
2018-03-29 14:15:46 +03:00
|
|
|
ServoStyleSet* servoSet = presShell->StyleSet();
|
2017-12-04 04:47:54 +03:00
|
|
|
servoSet->StyleNewSubtree(mElement);
|
|
|
|
}
|
2016-12-14 06:11:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Element* mElement;
|
2017-11-17 22:52:29 +03:00
|
|
|
bool mHadData;
|
2017-12-04 04:47:54 +03:00
|
|
|
bool* mResolveStyle;
|
2016-12-14 06:11:28 +03:00
|
|
|
};
|
2011-11-04 00:39:07 +04:00
|
|
|
|
2018-11-03 14:11:31 +03:00
|
|
|
static bool IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal) {
|
|
|
|
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
aPrincipal->GetURI(getter_AddRefs(uri));
|
|
|
|
NS_ENSURE_TRUE(uri, false);
|
|
|
|
|
|
|
|
bool isChrome = false;
|
|
|
|
return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome;
|
|
|
|
}
|
|
|
|
|
2000-01-12 12:32:29 +03:00
|
|
|
// This function loads a particular XBL file and installs all of the bindings
|
|
|
|
// onto the element.
|
2017-12-05 20:05:51 +03:00
|
|
|
nsresult nsXBLService::LoadBindings(Element* aElement, nsIURI* aURL,
|
2013-01-24 21:45:50 +04:00
|
|
|
nsIPrincipal* aOriginPrincipal,
|
2014-03-19 01:25:39 +04:00
|
|
|
nsXBLBinding** aBinding,
|
|
|
|
bool* aResolveStyle) {
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(aOriginPrincipal, "Must have an origin principal");
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
*aBinding = nullptr;
|
2011-10-17 18:59:28 +04:00
|
|
|
*aResolveStyle = false;
|
2000-07-28 04:35:02 +04:00
|
|
|
|
2017-12-05 20:05:51 +03:00
|
|
|
AutoEnsureSubtreeStyled subtreeStyled(aElement);
|
2017-11-24 17:15:38 +03:00
|
|
|
|
|
|
|
if (MOZ_UNLIKELY(!aURL)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-11-03 14:11:31 +03:00
|
|
|
#ifdef DEBUG
|
2019-01-25 18:07:06 +03:00
|
|
|
// Ensures that XBL bindings are not used in the following conditions:
|
2018-11-03 14:11:31 +03:00
|
|
|
//
|
|
|
|
// 1) In the content process
|
|
|
|
// 2) In a document that disallows XUL/XBL which only loads bindings
|
|
|
|
// referenced in a chrome stylesheet.
|
|
|
|
//
|
2019-01-25 18:07:06 +03:00
|
|
|
// If the conditions are met, trigger an assertion since there shouldn't
|
|
|
|
// be this kind of binding usage.
|
2018-11-03 14:11:31 +03:00
|
|
|
//
|
|
|
|
// The assertion might not catch all violations because (2) is needed
|
|
|
|
// for the current test setup. Someone may unknownly using a binding
|
|
|
|
// in AllowXULXBL() documents in content process in production without
|
|
|
|
// knowing.
|
|
|
|
if (XRE_IsContentProcess() &&
|
|
|
|
IsSystemOrChromeURLPrincipal(aOriginPrincipal) && aElement->OwnerDoc() &&
|
2019-01-25 18:07:06 +03:00
|
|
|
!aElement->OwnerDoc()->AllowXULXBL()) {
|
2019-01-26 10:51:10 +03:00
|
|
|
MOZ_ASSERT(false, "Unexpected XBL binding used in the content process");
|
2018-11-03 14:11:31 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-11-24 17:15:38 +03:00
|
|
|
// Easy case: The binding was already loaded.
|
2017-12-05 20:05:51 +03:00
|
|
|
nsXBLBinding* binding = aElement->GetXBLBinding();
|
2017-11-24 17:15:38 +03:00
|
|
|
if (binding && !binding->MarkedForDeath() &&
|
|
|
|
binding->PrototypeBinding()->CompareBindingURI(aURL)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2000-01-13 05:23:54 +03:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> document = aElement->OwnerDoc();
|
2001-07-04 09:54:09 +04:00
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString urlspec;
|
2018-11-03 02:15:26 +03:00
|
|
|
nsresult rv = aURL->GetSpec(urlspec);
|
2016-09-19 16:50:22 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2017-11-20 15:07:53 +03:00
|
|
|
if (binding) {
|
2017-12-05 20:05:51 +03:00
|
|
|
FlushStyleBindings(aElement);
|
2017-11-24 17:15:38 +03:00
|
|
|
binding = nullptr;
|
2000-04-27 06:08:35 +04:00
|
|
|
}
|
2000-01-13 11:54:16 +03:00
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
bool ready;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsXBLBinding> newBinding;
|
2017-12-05 20:05:51 +03:00
|
|
|
if (NS_FAILED(rv = GetBinding(aElement, aURL, false, aOriginPrincipal, &ready,
|
2007-07-19 01:56:57 +04:00
|
|
|
getter_AddRefs(newBinding)))) {
|
2000-01-12 12:57:45 +03:00
|
|
|
return rv;
|
|
|
|
}
|
2000-01-12 12:44:18 +03:00
|
|
|
|
2000-06-02 12:13:29 +04:00
|
|
|
if (!newBinding) {
|
2003-10-02 02:53:56 +04:00
|
|
|
#ifdef DEBUG
|
2016-08-26 09:02:31 +03:00
|
|
|
nsAutoCString str(
|
|
|
|
NS_LITERAL_CSTRING(
|
|
|
|
"Failed to locate XBL binding. XBL is now using id instead of name "
|
|
|
|
"to reference bindings. Make sure you have switched over. The "
|
|
|
|
"invalid binding name is: ") +
|
|
|
|
aURL->GetSpecOrDefault());
|
2001-10-27 10:44:19 +04:00
|
|
|
NS_ERROR(str.get());
|
2003-10-02 02:53:56 +04:00
|
|
|
#endif
|
2000-08-04 12:45:29 +04:00
|
|
|
return NS_OK;
|
2000-03-30 07:18:44 +04:00
|
|
|
}
|
|
|
|
|
2017-12-05 20:05:51 +03:00
|
|
|
if (::IsAncestorBinding(document, aURL, aElement)) {
|
2006-10-08 14:18:41 +04:00
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
}
|
|
|
|
|
2017-12-05 20:05:51 +03:00
|
|
|
AutoStyleElement styleElement(aElement, aResolveStyle);
|
2017-11-24 17:15:38 +03:00
|
|
|
|
2013-01-24 21:45:50 +04:00
|
|
|
// We loaded a style binding. It goes on the end.
|
2017-11-24 17:15:38 +03:00
|
|
|
// Install the binding on the content node.
|
2017-12-05 20:05:51 +03:00
|
|
|
aElement->SetXBLBinding(newBinding);
|
2000-06-02 12:13:29 +04:00
|
|
|
|
2009-11-18 18:14:14 +03:00
|
|
|
{
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
2000-01-13 05:23:54 +03:00
|
|
|
|
2009-11-18 18:14:14 +03:00
|
|
|
// Set the binding's bound element.
|
2017-12-05 20:05:51 +03:00
|
|
|
newBinding->SetBoundElement(aElement);
|
2000-01-13 11:54:16 +03:00
|
|
|
|
2009-11-18 18:14:14 +03:00
|
|
|
// Tell the binding to build the anonymous content.
|
|
|
|
newBinding->GenerateAnonymousContent();
|
2008-03-15 02:08:57 +03:00
|
|
|
|
2009-11-18 18:14:14 +03:00
|
|
|
// Tell the binding to install event handlers
|
|
|
|
newBinding->InstallEventHandlers();
|
2008-03-15 02:08:57 +03:00
|
|
|
|
2009-11-18 18:14:14 +03:00
|
|
|
// Set up our properties
|
|
|
|
rv = newBinding->InstallImplementation();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Figure out if we have any scoped sheets. If so, we do a second resolve.
|
|
|
|
*aResolveStyle = newBinding->HasStyleSheets();
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2016-07-21 01:19:00 +03:00
|
|
|
newBinding.forget(aBinding);
|
2009-11-18 18:14:14 +03:00
|
|
|
}
|
2007-10-27 04:14:43 +04:00
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
return NS_OK;
|
2000-01-12 12:32:29 +03:00
|
|
|
}
|
|
|
|
|
2017-12-05 20:05:51 +03:00
|
|
|
void nsXBLService::FlushStyleBindings(Element* aElement) {
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> document = aElement->OwnerDoc();
|
2001-07-04 09:54:09 +04:00
|
|
|
|
2017-12-05 20:05:51 +03:00
|
|
|
nsXBLBinding* binding = aElement->GetXBLBinding();
|
2000-04-03 11:13:07 +04:00
|
|
|
if (binding) {
|
2013-07-11 19:58:28 +04:00
|
|
|
// Clear out the script references.
|
|
|
|
binding->ChangeDocument(document, nullptr);
|
2000-06-02 12:13:29 +04:00
|
|
|
|
2017-12-05 20:05:51 +03:00
|
|
|
aElement->SetXBLBinding(nullptr); // Flush old style bindings
|
2000-04-03 11:13:07 +04:00
|
|
|
}
|
2000-03-28 04:41:33 +04:00
|
|
|
}
|
|
|
|
|
2000-11-29 09:01:33 +03:00
|
|
|
//
|
|
|
|
// AttachGlobalKeyHandler
|
|
|
|
//
|
|
|
|
// Creates a new key handler and prepares to listen to key events on the given
|
|
|
|
// event receiver (either a document or an content node). If the receiver is
|
|
|
|
// content, then extra work needs to be done to hook it up to the document (XXX
|
|
|
|
// WHY??)
|
|
|
|
//
|
2013-04-06 04:44:26 +04:00
|
|
|
nsresult nsXBLService::AttachGlobalKeyHandler(EventTarget* aTarget) {
|
2000-11-29 09:01:33 +03:00
|
|
|
// check if the receiver is a content node (not a document), and hook
|
|
|
|
// it to the document if that is the case.
|
2013-04-06 04:44:26 +04:00
|
|
|
nsCOMPtr<EventTarget> piTarget = aTarget;
|
2007-05-14 13:11:38 +04:00
|
|
|
nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
|
2000-11-29 09:01:33 +03:00
|
|
|
if (contentNode) {
|
2004-12-02 05:24:28 +03:00
|
|
|
// Only attach if we're really in a document
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc = contentNode->GetUncomposedDoc();
|
2011-06-24 06:18:02 +04:00
|
|
|
if (doc) piTarget = doc; // We're a XUL keyset. Attach to our document.
|
2000-09-22 09:02:20 +04:00
|
|
|
}
|
2011-06-24 06:18:02 +04:00
|
|
|
|
2016-06-07 08:24:48 +03:00
|
|
|
if (!piTarget) return NS_ERROR_FAILURE;
|
2013-04-06 04:44:26 +04:00
|
|
|
|
2016-06-07 08:24:48 +03:00
|
|
|
EventListenerManager* manager = piTarget->GetOrCreateListenerManager();
|
2000-09-22 09:02:20 +04:00
|
|
|
if (!manager) return NS_ERROR_FAILURE;
|
2008-08-06 18:32:09 +04:00
|
|
|
|
|
|
|
// the listener already exists, so skip this
|
|
|
|
if (contentNode && contentNode->GetProperty(nsGkAtoms::listener))
|
|
|
|
return NS_OK;
|
2013-04-14 22:27:33 +04:00
|
|
|
|
2018-05-30 17:56:24 +03:00
|
|
|
Element* elt = Element::FromNodeOrNull(contentNode);
|
2000-09-22 09:02:20 +04:00
|
|
|
|
2000-11-29 09:01:33 +03:00
|
|
|
// Create the key handler
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsXBLWindowKeyHandler> handler =
|
2013-04-14 22:27:33 +04:00
|
|
|
NS_NewXBLWindowKeyHandler(elt, piTarget);
|
2000-09-22 09:02:20 +04:00
|
|
|
|
2016-03-16 04:58:28 +03:00
|
|
|
handler->InstallKeyboardEventListenersTo(manager);
|
2014-03-18 19:16:47 +04:00
|
|
|
|
2008-08-06 18:32:09 +04:00
|
|
|
if (contentNode)
|
2014-03-15 23:00:15 +04:00
|
|
|
return contentNode->SetProperty(nsGkAtoms::listener,
|
|
|
|
handler.forget().take(),
|
2011-10-17 18:59:28 +04:00
|
|
|
nsPropertyTable::SupportsDtorFunc, true);
|
2008-08-06 18:32:09 +04:00
|
|
|
|
2013-04-14 22:27:33 +04:00
|
|
|
// The reference to the handler will be maintained by the event target,
|
2008-08-06 18:32:09 +04:00
|
|
|
// and, if there is a content node, the property.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// DetachGlobalKeyHandler
|
|
|
|
//
|
|
|
|
// Removes a key handler added by DeatchGlobalKeyHandler.
|
|
|
|
//
|
2013-04-06 04:44:26 +04:00
|
|
|
nsresult nsXBLService::DetachGlobalKeyHandler(EventTarget* aTarget) {
|
|
|
|
nsCOMPtr<EventTarget> piTarget = aTarget;
|
2008-08-06 18:32:09 +04:00
|
|
|
nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
|
|
|
|
if (!contentNode) // detaching is only supported for content nodes
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Only attach if we're really in a document
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc = contentNode->GetUncomposedDoc();
|
2018-10-02 00:38:01 +03:00
|
|
|
if (doc) piTarget = doc;
|
2011-06-24 06:18:02 +04:00
|
|
|
|
2016-06-07 08:24:48 +03:00
|
|
|
if (!piTarget) return NS_ERROR_FAILURE;
|
2013-04-06 04:44:26 +04:00
|
|
|
|
2016-06-07 08:24:48 +03:00
|
|
|
EventListenerManager* manager = piTarget->GetOrCreateListenerManager();
|
2008-08-06 18:32:09 +04:00
|
|
|
if (!manager) return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsIDOMEventListener* handler = static_cast<nsIDOMEventListener*>(
|
|
|
|
contentNode->GetProperty(nsGkAtoms::listener));
|
|
|
|
if (!handler) return NS_ERROR_FAILURE;
|
|
|
|
|
2016-03-16 04:58:28 +03:00
|
|
|
static_cast<nsXBLWindowKeyHandler*>(handler)
|
|
|
|
->RemoveKeyboardEventListenersFrom(manager);
|
2014-03-18 19:16:47 +04:00
|
|
|
|
2008-08-06 18:32:09 +04:00
|
|
|
contentNode->DeleteProperty(nsGkAtoms::listener);
|
2000-09-22 09:02:20 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-11-28 03:54:56 +03:00
|
|
|
// Internal helper methods /////////////////////////////////////////////////////
|
2000-01-12 12:57:45 +03:00
|
|
|
|
2012-05-23 22:46:04 +04:00
|
|
|
nsresult nsXBLService::BindingReady(nsIContent* aBoundElement, nsIURI* aURI,
|
|
|
|
bool* aIsReady) {
|
2007-07-19 01:56:57 +04:00
|
|
|
// Don't do a security check here; we know this binding is set to go.
|
2012-07-30 18:20:58 +04:00
|
|
|
return GetBinding(aBoundElement, aURI, true, nullptr, aIsReady, nullptr);
|
2000-08-14 08:04:18 +04:00
|
|
|
}
|
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
nsresult nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aPeekOnly,
|
|
|
|
nsIPrincipal* aOriginPrincipal,
|
|
|
|
bool* aIsReady, nsXBLBinding** aResult) {
|
2006-11-09 04:58:12 +03:00
|
|
|
// More than 6 binding URIs are rare, see bug 55070 comment 18.
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsCOMPtr<nsIURI>, 6> uris;
|
2007-07-19 01:56:57 +04:00
|
|
|
return GetBinding(aBoundElement, aURI, aPeekOnly, aOriginPrincipal, aIsReady,
|
|
|
|
aResult, uris);
|
2006-11-09 04:58:12 +03:00
|
|
|
}
|
|
|
|
|
2014-08-12 07:06:55 +04:00
|
|
|
static bool MayBindToContent(nsXBLPrototypeBinding* aProtoBinding,
|
|
|
|
nsIContent* aBoundElement, nsIURI* aURI) {
|
|
|
|
// If this binding explicitly allows untrusted content, we're done.
|
|
|
|
if (aProtoBinding->BindToUntrustedContent()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We let XUL content and content in XUL documents through, since XUL is
|
|
|
|
// restricted anyway and we want to minimize remote XUL breakage.
|
2015-03-03 14:08:59 +03:00
|
|
|
if (aBoundElement->IsXULElement() ||
|
|
|
|
aBoundElement->OwnerDoc()->IsXULElement()) {
|
2014-08-12 07:06:55 +04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Similarly, we make an exception for anonymous content (which
|
|
|
|
// lives in the XBL scope), because it's already protected from content,
|
|
|
|
// and tends to use a lot of bindings that we wouldn't otherwise need to
|
|
|
|
// whitelist.
|
|
|
|
if (aBoundElement->IsInAnonymousSubtree()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow if the bound content subsumes the binding.
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> bindingDoc =
|
2014-08-12 07:06:55 +04:00
|
|
|
aProtoBinding->XBLDocumentInfo()->GetDocument();
|
|
|
|
NS_ENSURE_TRUE(bindingDoc, false);
|
|
|
|
if (aBoundElement->NodePrincipal()->Subsumes(bindingDoc->NodePrincipal())) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// One last special case: we need to watch out for in-document data: URI
|
|
|
|
// bindings from remote-XUL-whitelisted domains (especially tests), because
|
|
|
|
// they end up with a null principal (rather than inheriting the document's
|
|
|
|
// principal), which causes them to fail the check above.
|
|
|
|
if (nsContentUtils::AllowXULXBLForPrincipal(aBoundElement->NodePrincipal())) {
|
|
|
|
bool isDataURI = false;
|
|
|
|
nsresult rv = aURI->SchemeIs("data", &isDataURI);
|
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
if (isDataURI) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disallow.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-19 01:25:39 +04:00
|
|
|
nsresult nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aPeekOnly,
|
|
|
|
nsIPrincipal* aOriginPrincipal,
|
|
|
|
bool* aIsReady, nsXBLBinding** aResult,
|
2015-09-10 00:08:10 +03:00
|
|
|
nsTArray<nsCOMPtr<nsIURI>>& aDontExtendURIs) {
|
2006-04-15 05:52:32 +04:00
|
|
|
NS_ASSERTION(aPeekOnly || aResult,
|
|
|
|
"Must have non-null out param if not just peeking to see "
|
|
|
|
"whether the binding is ready");
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
if (aResult) *aResult = nullptr;
|
2000-01-13 05:23:54 +03:00
|
|
|
|
|
|
|
if (!aURI) return NS_ERROR_FAILURE;
|
|
|
|
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString ref;
|
2011-05-22 05:12:46 +04:00
|
|
|
aURI->GetRef(ref);
|
2001-12-14 08:04:05 +03:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> boundDocument = aBoundElement->OwnerDoc();
|
2003-04-18 12:44:25 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsXBLDocumentInfo> docInfo;
|
2007-07-19 01:56:57 +04:00
|
|
|
nsresult rv =
|
|
|
|
LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI,
|
2011-10-17 18:59:28 +04:00
|
|
|
aOriginPrincipal, false, getter_AddRefs(docInfo));
|
2007-07-19 01:56:57 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2000-01-13 05:23:54 +03:00
|
|
|
if (!docInfo) return NS_ERROR_FAILURE;
|
|
|
|
|
2015-09-24 03:53:31 +03:00
|
|
|
WeakPtr<nsXBLPrototypeBinding> protoBinding =
|
|
|
|
docInfo->GetPrototypeBinding(ref);
|
2000-09-28 00:23:49 +04:00
|
|
|
|
2012-05-10 02:57:44 +04:00
|
|
|
if (!protoBinding) {
|
|
|
|
#ifdef DEBUG
|
2012-09-02 06:35:17 +04:00
|
|
|
nsAutoCString message("Unable to locate an XBL binding for URI ");
|
2016-08-26 09:02:31 +03:00
|
|
|
message += aURI->GetSpecOrDefault();
|
2012-05-10 02:57:44 +04:00
|
|
|
message += " in document ";
|
2016-08-26 09:02:31 +03:00
|
|
|
message += boundDocument->GetDocumentURI()->GetSpecOrDefault();
|
2012-05-10 02:57:44 +04:00
|
|
|
NS_WARNING(message.get());
|
|
|
|
#endif
|
2000-11-04 14:03:14 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
2012-05-10 02:57:44 +04:00
|
|
|
}
|
2000-10-17 01:46:59 +04:00
|
|
|
|
2014-08-12 07:06:55 +04:00
|
|
|
// If the binding isn't whitelisted, refuse to apply it to content that
|
|
|
|
// doesn't subsume it (modulo a few exceptions).
|
|
|
|
if (!MayBindToContent(protoBinding, aBoundElement, aURI)) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsAutoCString message("Permission denied to apply binding ");
|
2016-08-26 09:02:31 +03:00
|
|
|
message += aURI->GetSpecOrDefault();
|
2014-08-12 07:06:55 +04:00
|
|
|
message +=
|
|
|
|
" to unprivileged content. Set bindToUntrustedContent=true on "
|
|
|
|
"the binding to override this restriction.";
|
|
|
|
NS_WARNING(message.get());
|
|
|
|
#endif
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2015-01-30 21:55:11 +03:00
|
|
|
aDontExtendURIs.AppendElement(protoBinding->BindingURI());
|
2009-11-04 00:45:10 +03:00
|
|
|
nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
|
|
|
|
if (altBindingURI) {
|
2015-01-30 21:55:11 +03:00
|
|
|
aDontExtendURIs.AppendElement(altBindingURI);
|
2009-11-04 00:45:10 +03:00
|
|
|
}
|
|
|
|
|
2001-03-10 04:43:09 +03:00
|
|
|
// Our prototype binding must have all its resources loaded.
|
2017-06-05 09:30:52 +03:00
|
|
|
bool ready = protoBinding->LoadResources(aBoundElement);
|
2001-03-10 04:43:09 +03:00
|
|
|
if (!ready) {
|
|
|
|
// Add our bound element to the protos list of elts that should
|
|
|
|
// be notified when the stylesheets and scripts finish loading.
|
|
|
|
protoBinding->AddResourceListener(aBoundElement);
|
|
|
|
return NS_ERROR_FAILURE; // The binding isn't ready yet.
|
|
|
|
}
|
|
|
|
|
2011-11-04 00:39:07 +04:00
|
|
|
rv = protoBinding->ResolveBaseBinding();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2015-09-10 00:08:10 +03:00
|
|
|
nsCOMPtr<nsIURI> baseBindingURI;
|
2015-09-24 03:53:31 +03:00
|
|
|
WeakPtr<nsXBLPrototypeBinding> baseProto = protoBinding->GetBasePrototype();
|
2000-09-28 00:23:49 +04:00
|
|
|
if (baseProto) {
|
2011-11-04 00:39:07 +04:00
|
|
|
baseBindingURI = baseProto->BindingURI();
|
|
|
|
} else {
|
|
|
|
baseBindingURI = protoBinding->GetBaseBindingURI();
|
|
|
|
if (baseBindingURI) {
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t count = aDontExtendURIs.Length();
|
|
|
|
for (uint32_t index = 0; index < count; ++index) {
|
2011-11-04 00:39:07 +04:00
|
|
|
bool equal;
|
|
|
|
rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
|
2003-11-18 00:03:32 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2011-11-04 00:39:07 +04:00
|
|
|
if (equal) {
|
2016-08-26 09:02:31 +03:00
|
|
|
NS_ConvertUTF8toUTF16 protoSpec(
|
|
|
|
protoBinding->BindingURI()->GetSpecOrDefault());
|
|
|
|
NS_ConvertUTF8toUTF16 baseSpec(baseBindingURI->GetSpecOrDefault());
|
|
|
|
const char16_t* params[] = {protoSpec.get(), baseSpec.get()};
|
2011-12-15 18:47:03 +04:00
|
|
|
nsContentUtils::ReportToConsole(
|
2013-08-21 23:28:26 +04:00
|
|
|
nsIScriptError::warningFlag, NS_LITERAL_CSTRING("XBL"), nullptr,
|
2011-12-15 18:47:03 +04:00
|
|
|
nsContentUtils::eXBL_PROPERTIES, "CircularExtendsBinding", params,
|
|
|
|
ArrayLength(params), boundDocument->GetDocumentURI());
|
2011-11-04 00:39:07 +04:00
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
2000-12-07 13:11:21 +03:00
|
|
|
}
|
|
|
|
}
|
2000-01-13 05:23:54 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsXBLBinding> baseBinding;
|
2011-11-04 00:39:07 +04:00
|
|
|
if (baseBindingURI) {
|
2015-09-10 00:08:10 +03:00
|
|
|
nsCOMPtr<nsIContent> child = protoBinding->GetBindingElement();
|
2011-11-04 00:39:07 +04:00
|
|
|
rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly,
|
|
|
|
child->NodePrincipal(), aIsReady,
|
|
|
|
getter_AddRefs(baseBinding), aDontExtendURIs);
|
|
|
|
if (NS_FAILED(rv)) return rv; // We aren't ready yet.
|
|
|
|
}
|
|
|
|
|
2011-10-17 18:59:28 +04:00
|
|
|
*aIsReady = true;
|
2011-11-04 00:39:07 +04:00
|
|
|
|
2000-09-28 00:23:49 +04:00
|
|
|
if (!aPeekOnly) {
|
|
|
|
// Make a new binding
|
2015-09-10 00:08:10 +03:00
|
|
|
NS_ENSURE_STATE(protoBinding);
|
2005-02-26 01:07:01 +03:00
|
|
|
nsXBLBinding* newBinding = new nsXBLBinding(protoBinding);
|
|
|
|
|
2011-11-04 00:39:07 +04:00
|
|
|
if (baseBinding) {
|
|
|
|
if (!baseProto) {
|
|
|
|
protoBinding->SetBasePrototype(baseBinding->PrototypeBinding());
|
|
|
|
}
|
|
|
|
newBinding->SetBaseBinding(baseBinding);
|
|
|
|
}
|
2005-02-26 01:07:01 +03:00
|
|
|
|
|
|
|
NS_ADDREF(*aResult = newBinding);
|
2000-09-28 00:23:49 +04:00
|
|
|
}
|
|
|
|
|
2000-01-13 05:23:54 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-11-18 00:03:32 +03:00
|
|
|
nsresult nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* aBoundDocument,
|
2003-11-18 00:03:32 +03:00
|
|
|
nsIURI* aBindingURI,
|
2007-07-19 01:56:57 +04:00
|
|
|
nsIPrincipal* aOriginPrincipal,
|
2011-09-29 10:19:26 +04:00
|
|
|
bool aForceSyncLoad,
|
2010-07-15 05:53:11 +04:00
|
|
|
nsXBLDocumentInfo** aResult) {
|
2018-04-28 22:50:58 +03:00
|
|
|
MOZ_ASSERT(aBindingURI, "Must have a binding URI");
|
|
|
|
MOZ_ASSERT(!aOriginPrincipal || aBoundDocument,
|
|
|
|
"If we're doing a security check, we better have a document!");
|
2014-03-19 01:25:39 +04:00
|
|
|
|
2015-09-15 04:59:35 +03:00
|
|
|
*aResult = nullptr;
|
2015-11-05 01:31:46 +03:00
|
|
|
// Allow XBL in unprivileged documents if it's specified in a privileged or
|
|
|
|
// chrome: stylesheet. This allows themes to specify XBL bindings.
|
|
|
|
if (aOriginPrincipal && !IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
|
2015-09-15 04:59:35 +03:00
|
|
|
NS_ENSURE_TRUE(!aBoundDocument || aBoundDocument->AllowXULXBL(),
|
|
|
|
NS_ERROR_XBL_BLOCKED);
|
2007-06-13 01:56:06 +04:00
|
|
|
}
|
2000-05-19 08:48:43 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsXBLDocumentInfo> info;
|
2000-12-02 13:34:52 +03:00
|
|
|
|
2007-02-24 19:27:51 +03:00
|
|
|
nsCOMPtr<nsIURI> documentURI;
|
2018-07-23 14:28:47 +03:00
|
|
|
nsresult rv = NS_GetURIWithoutRef(aBindingURI, getter_AddRefs(documentURI));
|
2003-11-18 00:03:32 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
nsBindingManager* bindingManager = nullptr;
|
|
|
|
|
|
|
|
// The first thing to check is the binding manager, which (if it exists)
|
|
|
|
// should have a reference to the nsXBLDocumentInfo if this document
|
|
|
|
// has ever loaded this binding before.
|
|
|
|
if (aBoundDocument) {
|
|
|
|
bindingManager = aBoundDocument->BindingManager();
|
|
|
|
info = bindingManager->GetXBLDocumentInfo(documentURI);
|
|
|
|
if (aBoundDocument->IsStaticDocument() &&
|
|
|
|
IsChromeOrResourceURI(aBindingURI)) {
|
|
|
|
aForceSyncLoad = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// It's possible the document is already being loaded. If so, there's no
|
|
|
|
// document yet, but we need to glom on our request so that it will be
|
|
|
|
// processed whenever the doc does finish loading.
|
|
|
|
NodeInfo* ni = nullptr;
|
|
|
|
if (aBoundElement) ni = aBoundElement->NodeInfo();
|
|
|
|
|
|
|
|
if (!info && bindingManager &&
|
|
|
|
(!ni ||
|
|
|
|
!(ni->Equals(nsGkAtoms::scrollbar, kNameSpaceID_XUL) ||
|
|
|
|
ni->Equals(nsGkAtoms::thumb, kNameSpaceID_XUL) ||
|
|
|
|
((ni->Equals(nsGkAtoms::input) || ni->Equals(nsGkAtoms::select)) &&
|
|
|
|
aBoundElement->IsHTMLElement()))) &&
|
|
|
|
!aForceSyncLoad) {
|
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
|
|
if (bindingManager)
|
|
|
|
listener = bindingManager->GetLoadingDocListener(documentURI);
|
|
|
|
if (listener) {
|
|
|
|
nsXBLStreamListener* xblListener =
|
|
|
|
static_cast<nsXBLStreamListener*>(listener.get());
|
|
|
|
// Create a new load observer.
|
|
|
|
if (!xblListener->HasRequest(aBindingURI, aBoundElement)) {
|
|
|
|
nsXBLBindingRequest* req =
|
|
|
|
new nsXBLBindingRequest(aBindingURI, aBoundElement);
|
|
|
|
xblListener->AddRequest(req);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-11 04:56:27 +04:00
|
|
|
#ifdef MOZ_XUL
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
// The second line of defense is the global nsXULPrototypeCache,
|
|
|
|
// if it's being used.
|
2007-03-12 08:53:33 +03:00
|
|
|
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
2014-03-19 01:25:39 +04:00
|
|
|
bool useXULCache = cache && cache->IsEnabled();
|
2001-02-22 06:01:34 +03:00
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
if (!info && useXULCache) {
|
2000-08-06 02:33:29 +04:00
|
|
|
// This cache crosses the entire product, so that any XBL bindings that are
|
|
|
|
// part of chrome will be reused across all XUL documents.
|
2018-03-28 18:31:23 +03:00
|
|
|
info = cache->GetXBLDocumentInfo(documentURI);
|
2000-08-06 02:33:29 +04:00
|
|
|
}
|
2000-08-22 02:30:36 +04:00
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
|
2011-11-04 00:39:08 +04:00
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
if (!info) {
|
2011-11-04 00:39:08 +04:00
|
|
|
// Next, look in the startup cache
|
|
|
|
if (!info && useStartupCache) {
|
2017-05-12 03:16:27 +03:00
|
|
|
rv = nsXBLDocumentInfo::ReadPrototypeBindings(
|
|
|
|
documentURI, getter_AddRefs(info), aBoundDocument);
|
2011-11-04 00:39:08 +04:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
cache->PutXBLDocumentInfo(info);
|
|
|
|
}
|
|
|
|
}
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
}
|
2011-11-04 00:39:08 +04:00
|
|
|
#endif
|
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
if (!info) {
|
|
|
|
// Finally, if all lines of defense fail, we go and fetch the binding
|
|
|
|
// document.
|
|
|
|
|
|
|
|
// Always load chrome synchronously
|
|
|
|
bool chrome;
|
|
|
|
if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
|
|
|
|
aForceSyncLoad = true;
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> document;
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
rv = FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
|
|
|
|
aBindingURI, aOriginPrincipal, aForceSyncLoad,
|
|
|
|
getter_AddRefs(document));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-11-11 04:15:22 +03:00
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
if (document) {
|
|
|
|
nsBindingManager* xblDocBindingManager = document->BindingManager();
|
|
|
|
info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
|
|
|
|
if (!info) {
|
|
|
|
NS_ERROR(
|
|
|
|
"An XBL file is malformed. Did you forget the XBL namespace on "
|
|
|
|
"the bindings tag?");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
xblDocBindingManager->RemoveXBLDocumentInfo(
|
|
|
|
info); // Break the self-imposed cycle.
|
2011-11-04 00:39:08 +04:00
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
// If the doc is a chrome URI, then we put it into the XUL cache.
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
if (useStartupCache) {
|
|
|
|
cache->PutXBLDocumentInfo(info);
|
2014-03-19 01:25:39 +04:00
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
// now write the bindings into the startup cache
|
|
|
|
info->WritePrototypeBindings();
|
2000-05-19 08:48:43 +04:00
|
|
|
}
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
#endif
|
2000-01-12 12:57:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Bug 1166351 - Prioritize getting the nsXBLDocumentInfo out of the bound document's nsBindingManager instead of the nsXULPrototypeCache. r=bobbyholley+313730
This is kind of a long story, stay with me on this.
In bug 990290, a WeakMap was added to any JS scope that loaded an XBL
binding. That WeakMap stored the JS prototypes that are injected into
a bound node's prototype chain.
When a binding is removed, we search the prototype chain for the
JS prototype that we'd added, and remove it.
The XUL prototype cache caches numerous things, including nsXBLDocumentInfo,
which we use to get at the nsXBLPrototypeBinding for a particular binding,
which is then used to generate the class object that's put into the WeakMap.
When the XUL prototype cache is flushed, that means that when a binding
is bound, its definition needs to be reloaded off of the disk. If, however,
there was a pre-existing instance of the binding already being used in a
document, now we were in a funny case.
We were in a funny case, because when attempting to remove a binding, we
would look up the nsXBLPrototypeBinding via the nsXBLDocumentInfo that's
being held within the nsXULPrototypeCache, find (or load off the disk) a
_new_ nsXBLDocumentInfo and generate a _new_ nsXBLPrototypeBinding that
did not match to the one that we'd already stored in the WeakMap. This
would mean that removal would go wrong, and things would break horribly.
This patch makes it so that we prioritize checking the nsBindingManager
for a document for the nsXBLDocumentInfo before checking the
global nsXULPrototypeCache. That way, even if the cache gets cleared,
if the binding was ever used in this document, it'll be in the
nsBindingManager, and we'll get the same nsXULProtoypeBinding that
we'd been using before, and sanity will prevail.
MozReview-Commit-ID: G8iLDbCPRAC
--HG--
extra : rebase_source : 4322965c0b7150b22454651ad7a9461ee76d766b
2016-05-17 02:07:26 +03:00
|
|
|
if (info && bindingManager) {
|
|
|
|
// Cache it in our binding manager's document table. This way,
|
|
|
|
// we can ensure that if the document has loaded this binding
|
|
|
|
// before, it can continue to use it even if the XUL prototype
|
|
|
|
// cache gets flushed. That way, if a flush does occur, we
|
|
|
|
// don't get into a weird state where we're using different
|
|
|
|
// XBLDocumentInfos for the same XBL document in a single
|
|
|
|
// document that has loaded some bindings.
|
|
|
|
bindingManager->PutXBLDocumentInfo(info);
|
|
|
|
}
|
|
|
|
|
2012-03-23 00:46:03 +04:00
|
|
|
info.forget(aResult);
|
2000-01-12 12:57:45 +03:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2000-08-22 02:30:36 +04:00
|
|
|
nsresult nsXBLService::FetchBindingDocument(
|
2019-01-02 16:05:23 +03:00
|
|
|
nsIContent* aBoundElement, Document* aBoundDocument, nsIURI* aDocumentURI,
|
|
|
|
nsIURI* aBindingURI, nsIPrincipal* aOriginPrincipal, bool aForceSyncLoad,
|
|
|
|
Document** aResult) {
|
2002-10-09 11:03:15 +04:00
|
|
|
nsresult rv = NS_OK;
|
2012-07-30 18:20:58 +04:00
|
|
|
// Initialize our out pointer to nullptr
|
|
|
|
*aResult = nullptr;
|
2000-01-12 13:20:11 +03:00
|
|
|
|
2009-01-14 01:53:04 +03:00
|
|
|
// Now we have to synchronously load the binding file.
|
2014-03-19 01:25:39 +04:00
|
|
|
// Create an XML content sink and a parser.
|
2000-08-12 10:28:02 +04:00
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
2003-10-22 10:09:48 +04:00
|
|
|
if (aBoundDocument) loadGroup = aBoundDocument->GetDocumentLoadGroup();
|
2000-01-12 13:20:11 +03:00
|
|
|
|
2006-04-04 06:41:04 +04:00
|
|
|
// We really shouldn't have to force a sync load for anything here... could
|
|
|
|
// we get away with not doing that? Not sure.
|
|
|
|
if (IsChromeOrResourceURI(aDocumentURI)) aForceSyncLoad = true;
|
2000-12-02 13:34:52 +03:00
|
|
|
|
2006-06-16 00:30:44 +04:00
|
|
|
// Create document and contentsink and set them up.
|
2019-01-02 16:05:23 +03:00
|
|
|
nsCOMPtr<Document> doc;
|
2006-06-16 00:30:44 +04:00
|
|
|
rv = NS_NewXMLDocument(getter_AddRefs(doc));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-10-09 11:03:15 +04:00
|
|
|
|
2017-10-11 01:25:10 +03:00
|
|
|
// XBL documents must allow XUL and XBL elements in them but the usual check
|
|
|
|
// only checks if the document is loaded in the system principal which is
|
|
|
|
// sometimes not the case.
|
|
|
|
doc->ForceEnableXULXBL();
|
|
|
|
|
2006-06-16 00:30:44 +04:00
|
|
|
nsCOMPtr<nsIXMLContentSink> xblSink;
|
2012-07-30 18:20:58 +04:00
|
|
|
rv =
|
|
|
|
NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nullptr);
|
2006-06-16 00:30:44 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-10-09 11:03:15 +04:00
|
|
|
|
2006-06-16 00:30:44 +04:00
|
|
|
// Open channel
|
2014-09-21 20:38:38 +04:00
|
|
|
// Note: There are some cases where aOriginPrincipal and aBoundDocument are
|
|
|
|
// purposely set to null (to bypass security checks) when calling
|
|
|
|
// LoadBindingDocumentInfo() which calls FetchBindingDocument(). LoadInfo
|
|
|
|
// will end up with no principal or node in those cases, so we use
|
|
|
|
// systemPrincipal. This achieves the same result of bypassing security
|
|
|
|
// checks, but it gives the wrong information to potential future consumers of
|
|
|
|
// loadInfo.
|
2006-06-16 00:30:44 +04:00
|
|
|
nsCOMPtr<nsIChannel> channel;
|
2014-11-14 19:56:55 +03:00
|
|
|
|
|
|
|
if (aOriginPrincipal) {
|
|
|
|
// if there is an originPrincipal we should also have aBoundDocument
|
2015-09-15 04:59:35 +03:00
|
|
|
MOZ_ASSERT(aBoundDocument,
|
|
|
|
"can not create a channel without aBoundDocument");
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2014-11-14 19:56:55 +03:00
|
|
|
rv = NS_NewChannelWithTriggeringPrincipal(
|
|
|
|
getter_AddRefs(channel), aDocumentURI, aBoundDocument, aOriginPrincipal,
|
2015-09-15 04:59:35 +03:00
|
|
|
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
|
|
|
|
nsILoadInfo::SEC_ALLOW_CHROME,
|
|
|
|
nsIContentPolicy::TYPE_XBL,
|
2018-01-24 19:17:31 +03:00
|
|
|
nullptr, // aPerformanceStorage
|
2014-11-14 19:56:55 +03:00
|
|
|
loadGroup);
|
|
|
|
} else {
|
|
|
|
rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI,
|
|
|
|
nsContentUtils::GetSystemPrincipal(),
|
2015-09-15 04:59:35 +03:00
|
|
|
nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS,
|
|
|
|
nsIContentPolicy::TYPE_XBL,
|
2019-03-08 12:04:11 +03:00
|
|
|
nullptr, // nsICookieSettings
|
2018-01-24 19:17:31 +03:00
|
|
|
nullptr, // PerformanceStorage
|
2014-11-14 19:56:55 +03:00
|
|
|
loadGroup);
|
|
|
|
}
|
2006-06-16 00:30:44 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-11-28 08:00:29 +03:00
|
|
|
|
2006-06-16 00:30:44 +04:00
|
|
|
if (!aForceSyncLoad) {
|
2000-08-12 10:28:02 +04:00
|
|
|
// We can be asynchronous
|
2009-01-14 14:24:26 +03:00
|
|
|
nsXBLStreamListener* xblListener =
|
2012-05-23 22:46:04 +04:00
|
|
|
new nsXBLStreamListener(aBoundDocument, xblSink, doc);
|
2001-06-20 05:11:56 +04:00
|
|
|
|
2000-08-06 08:57:55 +04:00
|
|
|
// Add ourselves to the list of loading docs.
|
2007-02-17 02:02:08 +03:00
|
|
|
nsBindingManager* bindingManager;
|
2001-08-01 11:50:47 +04:00
|
|
|
if (aBoundDocument)
|
2005-02-19 13:31:27 +03:00
|
|
|
bindingManager = aBoundDocument->BindingManager();
|
2003-10-22 10:09:48 +04:00
|
|
|
else
|
2012-07-30 18:20:58 +04:00
|
|
|
bindingManager = nullptr;
|
2003-10-22 10:09:48 +04:00
|
|
|
|
2001-08-01 11:50:47 +04:00
|
|
|
if (bindingManager)
|
2003-11-18 00:03:32 +03:00
|
|
|
bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
|
2000-08-06 08:57:55 +04:00
|
|
|
|
|
|
|
// Add our request.
|
2013-03-05 16:37:47 +04:00
|
|
|
nsXBLBindingRequest* req =
|
|
|
|
new nsXBLBindingRequest(aBindingURI, aBoundElement);
|
2000-08-06 08:57:55 +04:00
|
|
|
xblListener->AddRequest(req);
|
|
|
|
|
|
|
|
// Now kick off the async read.
|
2019-02-12 19:08:25 +03:00
|
|
|
rv = channel->AsyncOpen(xblListener);
|
2008-12-12 22:46:59 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Well, we won't be getting a load. Make sure to clean up our stuff!
|
|
|
|
if (bindingManager) {
|
|
|
|
bindingManager->RemoveLoadingDocListener(aDocumentURI);
|
|
|
|
}
|
|
|
|
}
|
2000-08-04 12:45:29 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-01-14 14:24:26 +03:00
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
|
|
rv = doc->StartDocumentLoad("loadAsInteractiveData", channel, loadGroup,
|
|
|
|
nullptr, getter_AddRefs(listener), true, xblSink);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2000-01-12 13:20:11 +03:00
|
|
|
// Now do a blocking synchronous parse of the file.
|
2006-06-16 00:30:44 +04:00
|
|
|
nsCOMPtr<nsIInputStream> in;
|
2019-02-12 19:08:25 +03:00
|
|
|
rv = channel->Open(getter_AddRefs(in));
|
2002-10-09 11:03:15 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2000-01-12 13:20:11 +03:00
|
|
|
|
2017-10-19 12:39:30 +03:00
|
|
|
rv = nsSyncLoadService::PushSyncStreamToListener(in.forget(), listener,
|
|
|
|
channel);
|
2002-10-09 11:03:15 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2000-01-12 13:20:11 +03:00
|
|
|
|
2006-06-16 00:30:44 +04:00
|
|
|
doc.swap(*aResult);
|
2000-01-12 13:20:11 +03:00
|
|
|
|
2006-06-16 00:30:44 +04:00
|
|
|
return NS_OK;
|
2000-01-12 12:32:29 +03:00
|
|
|
}
|