dom/xbl/nsXBLService.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/xbl/nsXBLService.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1060 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "mozilla/ArrayUtils.h"
    1.10 +
    1.11 +#include "nsCOMPtr.h"
    1.12 +#include "nsNetUtil.h"
    1.13 +#include "nsXBLService.h"
    1.14 +#include "nsXBLWindowKeyHandler.h"
    1.15 +#include "nsIInputStream.h"
    1.16 +#include "nsNameSpaceManager.h"
    1.17 +#include "nsIURI.h"
    1.18 +#include "nsIDOMElement.h"
    1.19 +#include "nsIURL.h"
    1.20 +#include "nsIChannel.h"
    1.21 +#include "nsXPIDLString.h"
    1.22 +#include "plstr.h"
    1.23 +#include "nsIContent.h"
    1.24 +#include "nsIDocument.h"
    1.25 +#include "nsIXMLContentSink.h"
    1.26 +#include "nsContentCID.h"
    1.27 +#include "mozilla/dom/XMLDocument.h"
    1.28 +#include "nsGkAtoms.h"
    1.29 +#include "nsIMemory.h"
    1.30 +#include "nsIObserverService.h"
    1.31 +#include "nsIDOMNodeList.h"
    1.32 +#include "nsXBLContentSink.h"
    1.33 +#include "nsXBLBinding.h"
    1.34 +#include "nsXBLPrototypeBinding.h"
    1.35 +#include "nsXBLDocumentInfo.h"
    1.36 +#include "nsCRT.h"
    1.37 +#include "nsContentUtils.h"
    1.38 +#include "nsSyncLoadService.h"
    1.39 +#include "nsContentPolicyUtils.h"
    1.40 +#include "nsTArray.h"
    1.41 +#include "nsError.h"
    1.42 +
    1.43 +#include "nsIPresShell.h"
    1.44 +#include "nsIDocumentObserver.h"
    1.45 +#include "nsFrameManager.h"
    1.46 +#include "nsStyleContext.h"
    1.47 +#include "nsIScriptSecurityManager.h"
    1.48 +#include "nsIScriptError.h"
    1.49 +#include "nsXBLSerialize.h"
    1.50 +
    1.51 +#ifdef MOZ_XUL
    1.52 +#include "nsXULPrototypeCache.h"
    1.53 +#endif
    1.54 +#include "nsIDOMEventListener.h"
    1.55 +#include "mozilla/Attributes.h"
    1.56 +#include "mozilla/EventListenerManager.h"
    1.57 +#include "mozilla/Preferences.h"
    1.58 +#include "mozilla/dom/Event.h"
    1.59 +#include "mozilla/dom/Element.h"
    1.60 +
    1.61 +using namespace mozilla;
    1.62 +using namespace mozilla::dom;
    1.63 +
    1.64 +#define NS_MAX_XBL_BINDING_RECURSION 20
    1.65 +
    1.66 +nsXBLService* nsXBLService::gInstance = nullptr;
    1.67 +
    1.68 +static bool
    1.69 +IsAncestorBinding(nsIDocument* aDocument,
    1.70 +                  nsIURI* aChildBindingURI,
    1.71 +                  nsIContent* aChild)
    1.72 +{
    1.73 +  NS_ASSERTION(aDocument, "expected a document");
    1.74 +  NS_ASSERTION(aChildBindingURI, "expected a binding URI");
    1.75 +  NS_ASSERTION(aChild, "expected a child content");
    1.76 +
    1.77 +  uint32_t bindingRecursion = 0;
    1.78 +  for (nsIContent *bindingParent = aChild->GetBindingParent();
    1.79 +       bindingParent;
    1.80 +       bindingParent = bindingParent->GetBindingParent()) {
    1.81 +    nsXBLBinding* binding = bindingParent->GetXBLBinding();
    1.82 +    if (!binding) {
    1.83 +      continue;
    1.84 +    }
    1.85 +
    1.86 +    if (binding->PrototypeBinding()->CompareBindingURI(aChildBindingURI)) {
    1.87 +      ++bindingRecursion;
    1.88 +      if (bindingRecursion < NS_MAX_XBL_BINDING_RECURSION) {
    1.89 +        continue;
    1.90 +      }
    1.91 +      nsAutoCString spec;
    1.92 +      aChildBindingURI->GetSpec(spec);
    1.93 +      NS_ConvertUTF8toUTF16 bindingURI(spec);
    1.94 +      const char16_t* params[] = { bindingURI.get() };
    1.95 +      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
    1.96 +                                      NS_LITERAL_CSTRING("XBL"), aDocument,
    1.97 +                                      nsContentUtils::eXBL_PROPERTIES,
    1.98 +                                      "TooDeepBindingRecursion",
    1.99 +                                      params, ArrayLength(params));
   1.100 +      return true;
   1.101 +    }
   1.102 +  }
   1.103 +
   1.104 +  return false;
   1.105 +}
   1.106 +
   1.107 +// Individual binding requests.
   1.108 +class nsXBLBindingRequest
   1.109 +{
   1.110 +public:
   1.111 +  nsCOMPtr<nsIURI> mBindingURI;
   1.112 +  nsCOMPtr<nsIContent> mBoundElement;
   1.113 +
   1.114 +  void DocumentLoaded(nsIDocument* aBindingDoc)
   1.115 +  {
   1.116 +    // We only need the document here to cause frame construction, so
   1.117 +    // we need the current doc, not the owner doc.
   1.118 +    nsIDocument* doc = mBoundElement->GetCurrentDoc();
   1.119 +    if (!doc)
   1.120 +      return;
   1.121 +
   1.122 +    // Get the binding.
   1.123 +    bool ready = false;
   1.124 +    nsXBLService::GetInstance()->BindingReady(mBoundElement, mBindingURI, &ready);
   1.125 +    if (!ready)
   1.126 +      return;
   1.127 +
   1.128 +    // If |mBoundElement| is (in addition to having binding |mBinding|)
   1.129 +    // also a descendant of another element with binding |mBinding|,
   1.130 +    // then we might have just constructed it due to the
   1.131 +    // notification of its parent.  (We can know about both if the
   1.132 +    // binding loads were triggered from the DOM rather than frame
   1.133 +    // construction.)  So we have to check both whether the element
   1.134 +    // has a primary frame and whether it's in the undisplayed map
   1.135 +    // before sending a ContentInserted notification, or bad things
   1.136 +    // will happen.
   1.137 +    nsIPresShell *shell = doc->GetShell();
   1.138 +    if (shell) {
   1.139 +      nsIFrame* childFrame = mBoundElement->GetPrimaryFrame();
   1.140 +      if (!childFrame) {
   1.141 +        // Check to see if it's in the undisplayed content map.
   1.142 +        nsStyleContext* sc =
   1.143 +          shell->FrameManager()->GetUndisplayedContent(mBoundElement);
   1.144 +
   1.145 +        if (!sc) {
   1.146 +          shell->RecreateFramesFor(mBoundElement);
   1.147 +        }
   1.148 +      }
   1.149 +    }
   1.150 +  }
   1.151 +
   1.152 +  nsXBLBindingRequest(nsIURI* aURI, nsIContent* aBoundElement)
   1.153 +    : mBindingURI(aURI),
   1.154 +      mBoundElement(aBoundElement)
   1.155 +  {
   1.156 +  }
   1.157 +};
   1.158 +
   1.159 +// nsXBLStreamListener, a helper class used for
   1.160 +// asynchronous parsing of URLs
   1.161 +/* Header file */
   1.162 +class nsXBLStreamListener MOZ_FINAL : public nsIStreamListener,
   1.163 +                                      public nsIDOMEventListener
   1.164 +{
   1.165 +public:
   1.166 +  NS_DECL_ISUPPORTS
   1.167 +  NS_DECL_NSISTREAMLISTENER
   1.168 +  NS_DECL_NSIREQUESTOBSERVER
   1.169 +  NS_DECL_NSIDOMEVENTLISTENER
   1.170 +
   1.171 +  nsXBLStreamListener(nsIDocument* aBoundDocument,
   1.172 +                      nsIXMLContentSink* aSink,
   1.173 +                      nsIDocument* aBindingDocument);
   1.174 +  ~nsXBLStreamListener();
   1.175 +
   1.176 +  void AddRequest(nsXBLBindingRequest* aRequest) { mBindingRequests.AppendElement(aRequest); }
   1.177 +  bool HasRequest(nsIURI* aURI, nsIContent* aBoundElement);
   1.178 +
   1.179 +private:
   1.180 +  nsCOMPtr<nsIStreamListener> mInner;
   1.181 +  nsAutoTArray<nsXBLBindingRequest*, 8> mBindingRequests;
   1.182 +
   1.183 +  nsCOMPtr<nsIWeakReference> mBoundDocument;
   1.184 +  nsCOMPtr<nsIXMLContentSink> mSink; // Only set until OnStartRequest
   1.185 +  nsCOMPtr<nsIDocument> mBindingDocument; // Only set until OnStartRequest
   1.186 +};
   1.187 +
   1.188 +/* Implementation file */
   1.189 +NS_IMPL_ISUPPORTS(nsXBLStreamListener,
   1.190 +                  nsIStreamListener,
   1.191 +                  nsIRequestObserver,
   1.192 +                  nsIDOMEventListener)
   1.193 +
   1.194 +nsXBLStreamListener::nsXBLStreamListener(nsIDocument* aBoundDocument,
   1.195 +                                         nsIXMLContentSink* aSink,
   1.196 +                                         nsIDocument* aBindingDocument)
   1.197 +: mSink(aSink), mBindingDocument(aBindingDocument)
   1.198 +{
   1.199 +  /* member initializers and constructor code */
   1.200 +  mBoundDocument = do_GetWeakReference(aBoundDocument);
   1.201 +}
   1.202 +
   1.203 +nsXBLStreamListener::~nsXBLStreamListener()
   1.204 +{
   1.205 +  for (uint32_t i = 0; i < mBindingRequests.Length(); i++) {
   1.206 +    nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
   1.207 +    delete req;
   1.208 +  }
   1.209 +}
   1.210 +
   1.211 +NS_IMETHODIMP
   1.212 +nsXBLStreamListener::OnDataAvailable(nsIRequest *request, nsISupports* aCtxt,
   1.213 +                                     nsIInputStream* aInStr,
   1.214 +                                     uint64_t aSourceOffset, uint32_t aCount)
   1.215 +{
   1.216 +  if (mInner)
   1.217 +    return mInner->OnDataAvailable(request, aCtxt, aInStr, aSourceOffset, aCount);
   1.218 +  return NS_ERROR_FAILURE;
   1.219 +}
   1.220 +
   1.221 +NS_IMETHODIMP
   1.222 +nsXBLStreamListener::OnStartRequest(nsIRequest* request, nsISupports* aCtxt)
   1.223 +{
   1.224 +  // Make sure we don't hold on to the sink and binding document past this point
   1.225 +  nsCOMPtr<nsIXMLContentSink> sink;
   1.226 +  mSink.swap(sink);
   1.227 +  nsCOMPtr<nsIDocument> doc;
   1.228 +  mBindingDocument.swap(doc);
   1.229 +
   1.230 +  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
   1.231 +  NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
   1.232 +
   1.233 +  nsCOMPtr<nsILoadGroup> group;
   1.234 +  request->GetLoadGroup(getter_AddRefs(group));
   1.235 +
   1.236 +  nsresult rv = doc->StartDocumentLoad("loadAsInteractiveData",
   1.237 +                                       channel,
   1.238 +                                       group,
   1.239 +                                       nullptr,
   1.240 +                                       getter_AddRefs(mInner),
   1.241 +                                       true,
   1.242 +                                       sink);
   1.243 +  NS_ENSURE_SUCCESS(rv, rv);
   1.244 +
   1.245 +  // Make sure to add ourselves as a listener after StartDocumentLoad,
   1.246 +  // since that resets the event listners on the document.
   1.247 +  doc->AddEventListener(NS_LITERAL_STRING("load"), this, false);
   1.248 +
   1.249 +  return mInner->OnStartRequest(request, aCtxt);
   1.250 +}
   1.251 +
   1.252 +NS_IMETHODIMP
   1.253 +nsXBLStreamListener::OnStopRequest(nsIRequest* request, nsISupports* aCtxt, nsresult aStatus)
   1.254 +{
   1.255 +  nsresult rv = NS_OK;
   1.256 +  if (mInner) {
   1.257 +     rv = mInner->OnStopRequest(request, aCtxt, aStatus);
   1.258 +  }
   1.259 +
   1.260 +  // Don't hold onto the inner listener; holding onto it can create a cycle
   1.261 +  // with the document
   1.262 +  mInner = nullptr;
   1.263 +
   1.264 +  return rv;
   1.265 +}
   1.266 +
   1.267 +bool
   1.268 +nsXBLStreamListener::HasRequest(nsIURI* aURI, nsIContent* aElt)
   1.269 +{
   1.270 +  // XXX Could be more efficient.
   1.271 +  uint32_t count = mBindingRequests.Length();
   1.272 +  for (uint32_t i = 0; i < count; i++) {
   1.273 +    nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
   1.274 +    bool eq;
   1.275 +    if (req->mBoundElement == aElt &&
   1.276 +        NS_SUCCEEDED(req->mBindingURI->Equals(aURI, &eq)) && eq)
   1.277 +      return true;
   1.278 +  }
   1.279 +
   1.280 +  return false;
   1.281 +}
   1.282 +
   1.283 +nsresult
   1.284 +nsXBLStreamListener::HandleEvent(nsIDOMEvent* aEvent)
   1.285 +{
   1.286 +  nsresult rv = NS_OK;
   1.287 +  uint32_t i;
   1.288 +  uint32_t count = mBindingRequests.Length();
   1.289 +
   1.290 +  // Get the binding document; note that we don't hold onto it in this object
   1.291 +  // to avoid creating a cycle
   1.292 +  Event* event = aEvent->InternalDOMEvent();
   1.293 +  EventTarget* target = event->GetCurrentTarget();
   1.294 +  nsCOMPtr<nsIDocument> bindingDocument = do_QueryInterface(target);
   1.295 +  NS_ASSERTION(bindingDocument, "Event not targeted at document?!");
   1.296 +
   1.297 +  // See if we're still alive.
   1.298 +  nsCOMPtr<nsIDocument> doc(do_QueryReferent(mBoundDocument));
   1.299 +  if (!doc) {
   1.300 +    NS_WARNING("XBL load did not complete until after document went away! Modal dialog bug?\n");
   1.301 +  }
   1.302 +  else {
   1.303 +    // We have to do a flush prior to notification of the document load.
   1.304 +    // This has to happen since the HTML content sink can be holding on
   1.305 +    // to notifications related to our children (e.g., if you bind to the
   1.306 +    // <body> tag) that result in duplication of content.
   1.307 +    // We need to get the sink's notifications flushed and then make the binding
   1.308 +    // ready.
   1.309 +    if (count > 0) {
   1.310 +      nsXBLBindingRequest* req = mBindingRequests.ElementAt(0);
   1.311 +      nsIDocument* document = req->mBoundElement->GetCurrentDoc();
   1.312 +      if (document)
   1.313 +        document->FlushPendingNotifications(Flush_ContentAndNotify);
   1.314 +    }
   1.315 +
   1.316 +    // Remove ourselves from the set of pending docs.
   1.317 +    nsBindingManager *bindingManager = doc->BindingManager();
   1.318 +    nsIURI* documentURI = bindingDocument->GetDocumentURI();
   1.319 +    bindingManager->RemoveLoadingDocListener(documentURI);
   1.320 +
   1.321 +    if (!bindingDocument->GetRootElement()) {
   1.322 +      // FIXME: How about an error console warning?
   1.323 +      NS_WARNING("XBL doc with no root element - this usually shouldn't happen");
   1.324 +      return NS_ERROR_FAILURE;
   1.325 +    }
   1.326 +
   1.327 +    // Put our doc info in the doc table.
   1.328 +    nsBindingManager *xblDocBindingManager = bindingDocument->BindingManager();
   1.329 +    nsRefPtr<nsXBLDocumentInfo> info =
   1.330 +      xblDocBindingManager->GetXBLDocumentInfo(documentURI);
   1.331 +    xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
   1.332 +    if (!info) {
   1.333 +      if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
   1.334 +        NS_WARNING("An XBL file is malformed. Did you forget the XBL namespace on the bindings tag?");
   1.335 +      }
   1.336 +      nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   1.337 +                                      NS_LITERAL_CSTRING("XBL"), nullptr,
   1.338 +                                      nsContentUtils::eXBL_PROPERTIES,
   1.339 +                                      "MalformedXBL",
   1.340 +                                      nullptr, 0, documentURI);
   1.341 +      return NS_ERROR_FAILURE;
   1.342 +    }
   1.343 +
   1.344 +    // If the doc is a chrome URI, then we put it into the XUL cache.
   1.345 +#ifdef MOZ_XUL
   1.346 +    if (nsXBLService::IsChromeOrResourceURI(documentURI)) {
   1.347 +      nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
   1.348 +      if (cache && cache->IsEnabled())
   1.349 +        cache->PutXBLDocumentInfo(info);
   1.350 +    }
   1.351 +#endif
   1.352 +
   1.353 +    bindingManager->PutXBLDocumentInfo(info);
   1.354 +
   1.355 +    // Notify all pending requests that their bindings are
   1.356 +    // ready and can be installed.
   1.357 +    for (i = 0; i < count; i++) {
   1.358 +      nsXBLBindingRequest* req = mBindingRequests.ElementAt(i);
   1.359 +      req->DocumentLoaded(bindingDocument);
   1.360 +    }
   1.361 +  }
   1.362 +
   1.363 +  target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false);
   1.364 +
   1.365 +  return rv;
   1.366 +}
   1.367 +
   1.368 +// Implementation /////////////////////////////////////////////////////////////////
   1.369 +
   1.370 +// Static member variable initialization
   1.371 +bool nsXBLService::gAllowDataURIs = false;
   1.372 +
   1.373 +// Implement our nsISupports methods
   1.374 +NS_IMPL_ISUPPORTS(nsXBLService, nsISupportsWeakReference)
   1.375 +
   1.376 +void
   1.377 +nsXBLService::Init()
   1.378 +{
   1.379 +  gInstance = new nsXBLService();
   1.380 +  NS_ADDREF(gInstance);
   1.381 +}
   1.382 +
   1.383 +// Constructors/Destructors
   1.384 +nsXBLService::nsXBLService(void)
   1.385 +{
   1.386 +  Preferences::AddBoolVarCache(&gAllowDataURIs, "layout.debug.enable_data_xbl");
   1.387 +}
   1.388 +
   1.389 +nsXBLService::~nsXBLService(void)
   1.390 +{
   1.391 +}
   1.392 +
   1.393 +// static
   1.394 +bool
   1.395 +nsXBLService::IsChromeOrResourceURI(nsIURI* aURI)
   1.396 +{
   1.397 +  bool isChrome = false;
   1.398 +  bool isResource = false;
   1.399 +  if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) &&
   1.400 +      NS_SUCCEEDED(aURI->SchemeIs("resource", &isResource)))
   1.401 +      return (isChrome || isResource);
   1.402 +  return false;
   1.403 +}
   1.404 +
   1.405 +
   1.406 +// This function loads a particular XBL file and installs all of the bindings
   1.407 +// onto the element.
   1.408 +nsresult
   1.409 +nsXBLService::LoadBindings(nsIContent* aContent, nsIURI* aURL,
   1.410 +                           nsIPrincipal* aOriginPrincipal,
   1.411 +                           nsXBLBinding** aBinding, bool* aResolveStyle)
   1.412 +{
   1.413 +  NS_PRECONDITION(aOriginPrincipal, "Must have an origin principal");
   1.414 +
   1.415 +  *aBinding = nullptr;
   1.416 +  *aResolveStyle = false;
   1.417 +
   1.418 +  nsresult rv;
   1.419 +
   1.420 +  nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
   1.421 +
   1.422 +  nsAutoCString urlspec;
   1.423 +  if (nsContentUtils::GetWrapperSafeScriptFilename(document, aURL, urlspec)) {
   1.424 +    // Block an attempt to load a binding that has special wrapper
   1.425 +    // automation needs.
   1.426 +
   1.427 +    return NS_OK;
   1.428 +  }
   1.429 +
   1.430 +  nsXBLBinding *binding = aContent->GetXBLBinding();
   1.431 +  if (binding) {
   1.432 +    if (binding->MarkedForDeath()) {
   1.433 +      FlushStyleBindings(aContent);
   1.434 +      binding = nullptr;
   1.435 +    }
   1.436 +    else {
   1.437 +      // See if the URIs match.
   1.438 +      if (binding->PrototypeBinding()->CompareBindingURI(aURL))
   1.439 +        return NS_OK;
   1.440 +      FlushStyleBindings(aContent);
   1.441 +      binding = nullptr;
   1.442 +    }
   1.443 +  }
   1.444 +
   1.445 +  bool ready;
   1.446 +  nsRefPtr<nsXBLBinding> newBinding;
   1.447 +  if (NS_FAILED(rv = GetBinding(aContent, aURL, false, aOriginPrincipal,
   1.448 +                                &ready, getter_AddRefs(newBinding)))) {
   1.449 +    return rv;
   1.450 +  }
   1.451 +
   1.452 +  if (!newBinding) {
   1.453 +#ifdef DEBUG
   1.454 +    nsAutoCString spec;
   1.455 +    aURL->GetSpec(spec);
   1.456 +    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: ") + spec);
   1.457 +    NS_ERROR(str.get());
   1.458 +#endif
   1.459 +    return NS_OK;
   1.460 +  }
   1.461 +
   1.462 +  if (::IsAncestorBinding(document, aURL, aContent)) {
   1.463 +    return NS_ERROR_ILLEGAL_VALUE;
   1.464 +  }
   1.465 +
   1.466 +  // We loaded a style binding.  It goes on the end.
   1.467 +  if (binding) {
   1.468 +    // Get the last binding that is in the append layer.
   1.469 +    binding->RootBinding()->SetBaseBinding(newBinding);
   1.470 +  }
   1.471 +  else {
   1.472 +    // Install the binding on the content node.
   1.473 +    aContent->SetXBLBinding(newBinding);
   1.474 +  }
   1.475 +
   1.476 +  {
   1.477 +    nsAutoScriptBlocker scriptBlocker;
   1.478 +
   1.479 +    // Set the binding's bound element.
   1.480 +    newBinding->SetBoundElement(aContent);
   1.481 +
   1.482 +    // Tell the binding to build the anonymous content.
   1.483 +    newBinding->GenerateAnonymousContent();
   1.484 +
   1.485 +    // Tell the binding to install event handlers
   1.486 +    newBinding->InstallEventHandlers();
   1.487 +
   1.488 +    // Set up our properties
   1.489 +    rv = newBinding->InstallImplementation();
   1.490 +    NS_ENSURE_SUCCESS(rv, rv);
   1.491 +
   1.492 +    // Figure out if we have any scoped sheets.  If so, we do a second resolve.
   1.493 +    *aResolveStyle = newBinding->HasStyleSheets();
   1.494 +
   1.495 +    newBinding.swap(*aBinding);
   1.496 +  }
   1.497 +
   1.498 +  return NS_OK;
   1.499 +}
   1.500 +
   1.501 +nsresult
   1.502 +nsXBLService::FlushStyleBindings(nsIContent* aContent)
   1.503 +{
   1.504 +  nsCOMPtr<nsIDocument> document = aContent->OwnerDoc();
   1.505 +
   1.506 +  nsXBLBinding *binding = aContent->GetXBLBinding();
   1.507 +  if (binding) {
   1.508 +    // Clear out the script references.
   1.509 +    binding->ChangeDocument(document, nullptr);
   1.510 +
   1.511 +    aContent->SetXBLBinding(nullptr); // Flush old style bindings
   1.512 +  }
   1.513 +
   1.514 +  return NS_OK;
   1.515 +}
   1.516 +
   1.517 +//
   1.518 +// AttachGlobalKeyHandler
   1.519 +//
   1.520 +// Creates a new key handler and prepares to listen to key events on the given
   1.521 +// event receiver (either a document or an content node). If the receiver is content,
   1.522 +// then extra work needs to be done to hook it up to the document (XXX WHY??)
   1.523 +//
   1.524 +nsresult
   1.525 +nsXBLService::AttachGlobalKeyHandler(EventTarget* aTarget)
   1.526 +{
   1.527 +  // check if the receiver is a content node (not a document), and hook
   1.528 +  // it to the document if that is the case.
   1.529 +  nsCOMPtr<EventTarget> piTarget = aTarget;
   1.530 +  nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
   1.531 +  if (contentNode) {
   1.532 +    // Only attach if we're really in a document
   1.533 +    nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
   1.534 +    if (doc)
   1.535 +      piTarget = doc; // We're a XUL keyset. Attach to our document.
   1.536 +  }
   1.537 +
   1.538 +  EventListenerManager* manager = piTarget->GetOrCreateListenerManager();
   1.539 +
   1.540 +  if (!piTarget || !manager)
   1.541 +    return NS_ERROR_FAILURE;
   1.542 +
   1.543 +  // the listener already exists, so skip this
   1.544 +  if (contentNode && contentNode->GetProperty(nsGkAtoms::listener))
   1.545 +    return NS_OK;
   1.546 +
   1.547 +  nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(contentNode));
   1.548 +
   1.549 +  // Create the key handler
   1.550 +  nsRefPtr<nsXBLWindowKeyHandler> handler =
   1.551 +    NS_NewXBLWindowKeyHandler(elt, piTarget);
   1.552 +
   1.553 +  // listen to these events
   1.554 +  manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
   1.555 +                                  TrustedEventsAtSystemGroupBubble());
   1.556 +  manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
   1.557 +                                  TrustedEventsAtSystemGroupBubble());
   1.558 +  manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
   1.559 +                                  TrustedEventsAtSystemGroupBubble());
   1.560 +
   1.561 +  // The capturing listener is only used for XUL keysets to properly handle
   1.562 +  // shortcut keys in a multi-process environment.
   1.563 +  manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
   1.564 +                                  TrustedEventsAtSystemGroupCapture());
   1.565 +  manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
   1.566 +                                  TrustedEventsAtSystemGroupCapture());
   1.567 +  manager->AddEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
   1.568 +                                  TrustedEventsAtSystemGroupCapture());
   1.569 +
   1.570 +  if (contentNode)
   1.571 +    return contentNode->SetProperty(nsGkAtoms::listener,
   1.572 +                                    handler.forget().take(),
   1.573 +                                    nsPropertyTable::SupportsDtorFunc, true);
   1.574 +
   1.575 +  // The reference to the handler will be maintained by the event target,
   1.576 +  // and, if there is a content node, the property.
   1.577 +  return NS_OK;
   1.578 +}
   1.579 +
   1.580 +//
   1.581 +// DetachGlobalKeyHandler
   1.582 +//
   1.583 +// Removes a key handler added by DeatchGlobalKeyHandler.
   1.584 +//
   1.585 +nsresult
   1.586 +nsXBLService::DetachGlobalKeyHandler(EventTarget* aTarget)
   1.587 +{
   1.588 +  nsCOMPtr<EventTarget> piTarget = aTarget;
   1.589 +  nsCOMPtr<nsIContent> contentNode(do_QueryInterface(aTarget));
   1.590 +  if (!contentNode) // detaching is only supported for content nodes
   1.591 +    return NS_ERROR_FAILURE;
   1.592 +
   1.593 +  // Only attach if we're really in a document
   1.594 +  nsCOMPtr<nsIDocument> doc = contentNode->GetCurrentDoc();
   1.595 +  if (doc)
   1.596 +    piTarget = do_QueryInterface(doc);
   1.597 +
   1.598 +  EventListenerManager* manager = piTarget->GetOrCreateListenerManager();
   1.599 +
   1.600 +  if (!piTarget || !manager)
   1.601 +    return NS_ERROR_FAILURE;
   1.602 +
   1.603 +  nsIDOMEventListener* handler =
   1.604 +    static_cast<nsIDOMEventListener*>(contentNode->GetProperty(nsGkAtoms::listener));
   1.605 +  if (!handler)
   1.606 +    return NS_ERROR_FAILURE;
   1.607 +
   1.608 +  manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
   1.609 +                                     TrustedEventsAtSystemGroupBubble());
   1.610 +  manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
   1.611 +                                     TrustedEventsAtSystemGroupBubble());
   1.612 +  manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
   1.613 +                                     TrustedEventsAtSystemGroupBubble());
   1.614 +
   1.615 +  manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keydown"),
   1.616 +                                     TrustedEventsAtSystemGroupCapture());
   1.617 +  manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keyup"),
   1.618 +                                     TrustedEventsAtSystemGroupCapture());
   1.619 +  manager->RemoveEventListenerByType(handler, NS_LITERAL_STRING("keypress"),
   1.620 +                                     TrustedEventsAtSystemGroupCapture());
   1.621 +
   1.622 +  contentNode->DeleteProperty(nsGkAtoms::listener);
   1.623 +
   1.624 +  return NS_OK;
   1.625 +}
   1.626 +
   1.627 +// Internal helper methods ////////////////////////////////////////////////////////////////
   1.628 +
   1.629 +nsresult
   1.630 +nsXBLService::BindingReady(nsIContent* aBoundElement,
   1.631 +                           nsIURI* aURI,
   1.632 +                           bool* aIsReady)
   1.633 +{
   1.634 +  // Don't do a security check here; we know this binding is set to go.
   1.635 +  return GetBinding(aBoundElement, aURI, true, nullptr, aIsReady, nullptr);
   1.636 +}
   1.637 +
   1.638 +nsresult
   1.639 +nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
   1.640 +                         bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
   1.641 +                         bool* aIsReady, nsXBLBinding** aResult)
   1.642 +{
   1.643 +  // More than 6 binding URIs are rare, see bug 55070 comment 18.
   1.644 +  nsAutoTArray<nsIURI*, 6> uris;
   1.645 +  return GetBinding(aBoundElement, aURI, aPeekOnly, aOriginPrincipal, aIsReady,
   1.646 +                    aResult, uris);
   1.647 +}
   1.648 +
   1.649 +nsresult
   1.650 +nsXBLService::GetBinding(nsIContent* aBoundElement, nsIURI* aURI,
   1.651 +                         bool aPeekOnly, nsIPrincipal* aOriginPrincipal,
   1.652 +                         bool* aIsReady, nsXBLBinding** aResult,
   1.653 +                         nsTArray<nsIURI*>& aDontExtendURIs)
   1.654 +{
   1.655 +  NS_ASSERTION(aPeekOnly || aResult,
   1.656 +               "Must have non-null out param if not just peeking to see "
   1.657 +               "whether the binding is ready");
   1.658 +
   1.659 +  if (aResult)
   1.660 +    *aResult = nullptr;
   1.661 +
   1.662 +  if (!aURI)
   1.663 +    return NS_ERROR_FAILURE;
   1.664 +
   1.665 +  nsAutoCString ref;
   1.666 +  aURI->GetRef(ref);
   1.667 +
   1.668 +  nsCOMPtr<nsIDocument> boundDocument = aBoundElement->OwnerDoc();
   1.669 +
   1.670 +  nsRefPtr<nsXBLDocumentInfo> docInfo;
   1.671 +  nsresult rv = LoadBindingDocumentInfo(aBoundElement, boundDocument, aURI,
   1.672 +                                        aOriginPrincipal,
   1.673 +                                        false, getter_AddRefs(docInfo));
   1.674 +  NS_ENSURE_SUCCESS(rv, rv);
   1.675 +
   1.676 +  if (!docInfo)
   1.677 +    return NS_ERROR_FAILURE;
   1.678 +
   1.679 +  nsXBLPrototypeBinding* protoBinding = docInfo->GetPrototypeBinding(ref);
   1.680 +
   1.681 +  if (!protoBinding) {
   1.682 +#ifdef DEBUG
   1.683 +    nsAutoCString uriSpec;
   1.684 +    aURI->GetSpec(uriSpec);
   1.685 +    nsAutoCString doc;
   1.686 +    boundDocument->GetDocumentURI()->GetSpec(doc);
   1.687 +    nsAutoCString message("Unable to locate an XBL binding for URI ");
   1.688 +    message += uriSpec;
   1.689 +    message += " in document ";
   1.690 +    message += doc;
   1.691 +    NS_WARNING(message.get());
   1.692 +#endif
   1.693 +    return NS_ERROR_FAILURE;
   1.694 +  }
   1.695 +
   1.696 +  NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(protoBinding->BindingURI()),
   1.697 +                 NS_ERROR_OUT_OF_MEMORY);
   1.698 +  nsCOMPtr<nsIURI> altBindingURI = protoBinding->AlternateBindingURI();
   1.699 +  if (altBindingURI) {
   1.700 +    NS_ENSURE_TRUE(aDontExtendURIs.AppendElement(altBindingURI),
   1.701 +                   NS_ERROR_OUT_OF_MEMORY);
   1.702 +  }
   1.703 +
   1.704 +  // Our prototype binding must have all its resources loaded.
   1.705 +  bool ready = protoBinding->LoadResources();
   1.706 +  if (!ready) {
   1.707 +    // Add our bound element to the protos list of elts that should
   1.708 +    // be notified when the stylesheets and scripts finish loading.
   1.709 +    protoBinding->AddResourceListener(aBoundElement);
   1.710 +    return NS_ERROR_FAILURE; // The binding isn't ready yet.
   1.711 +  }
   1.712 +
   1.713 +  rv = protoBinding->ResolveBaseBinding();
   1.714 +  NS_ENSURE_SUCCESS(rv, rv);
   1.715 +
   1.716 +  nsIURI* baseBindingURI;
   1.717 +  nsXBLPrototypeBinding* baseProto = protoBinding->GetBasePrototype();
   1.718 +  if (baseProto) {
   1.719 +    baseBindingURI = baseProto->BindingURI();
   1.720 +  }
   1.721 +  else {
   1.722 +    baseBindingURI = protoBinding->GetBaseBindingURI();
   1.723 +    if (baseBindingURI) {
   1.724 +      uint32_t count = aDontExtendURIs.Length();
   1.725 +      for (uint32_t index = 0; index < count; ++index) {
   1.726 +        bool equal;
   1.727 +        rv = aDontExtendURIs[index]->Equals(baseBindingURI, &equal);
   1.728 +        NS_ENSURE_SUCCESS(rv, rv);
   1.729 +        if (equal) {
   1.730 +          nsAutoCString spec, basespec;
   1.731 +          protoBinding->BindingURI()->GetSpec(spec);
   1.732 +          NS_ConvertUTF8toUTF16 protoSpec(spec);
   1.733 +          baseBindingURI->GetSpec(basespec);
   1.734 +          NS_ConvertUTF8toUTF16 baseSpecUTF16(basespec);
   1.735 +          const char16_t* params[] = { protoSpec.get(), baseSpecUTF16.get() };
   1.736 +          nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
   1.737 +                                          NS_LITERAL_CSTRING("XBL"), nullptr,
   1.738 +                                          nsContentUtils::eXBL_PROPERTIES,
   1.739 +                                          "CircularExtendsBinding",
   1.740 +                                          params, ArrayLength(params),
   1.741 +                                          boundDocument->GetDocumentURI());
   1.742 +          return NS_ERROR_ILLEGAL_VALUE;
   1.743 +        }
   1.744 +      }
   1.745 +    }
   1.746 +  }
   1.747 +
   1.748 +  nsRefPtr<nsXBLBinding> baseBinding;
   1.749 +  if (baseBindingURI) {
   1.750 +    nsIContent* child = protoBinding->GetBindingElement();
   1.751 +    rv = GetBinding(aBoundElement, baseBindingURI, aPeekOnly,
   1.752 +                    child->NodePrincipal(), aIsReady,
   1.753 +                    getter_AddRefs(baseBinding), aDontExtendURIs);
   1.754 +    if (NS_FAILED(rv))
   1.755 +      return rv; // We aren't ready yet.
   1.756 +  }
   1.757 +
   1.758 +  *aIsReady = true;
   1.759 +
   1.760 +  if (!aPeekOnly) {
   1.761 +    // Make a new binding
   1.762 +    nsXBLBinding *newBinding = new nsXBLBinding(protoBinding);
   1.763 +    NS_ENSURE_TRUE(newBinding, NS_ERROR_OUT_OF_MEMORY);
   1.764 +
   1.765 +    if (baseBinding) {
   1.766 +      if (!baseProto) {
   1.767 +        protoBinding->SetBasePrototype(baseBinding->PrototypeBinding());
   1.768 +      }
   1.769 +       newBinding->SetBaseBinding(baseBinding);
   1.770 +    }
   1.771 +
   1.772 +    NS_ADDREF(*aResult = newBinding);
   1.773 +  }
   1.774 +
   1.775 +  return NS_OK;
   1.776 +}
   1.777 +
   1.778 +static bool SchemeIs(nsIURI* aURI, const char* aScheme)
   1.779 +{
   1.780 +  nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
   1.781 +  NS_ENSURE_TRUE(baseURI, false);
   1.782 +
   1.783 +  bool isScheme = false;
   1.784 +  return NS_SUCCEEDED(baseURI->SchemeIs(aScheme, &isScheme)) && isScheme;
   1.785 +}
   1.786 +
   1.787 +static bool
   1.788 +IsSystemOrChromeURLPrincipal(nsIPrincipal* aPrincipal)
   1.789 +{
   1.790 +  if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
   1.791 +    return true;
   1.792 +  }
   1.793 +
   1.794 +  nsCOMPtr<nsIURI> uri;
   1.795 +  aPrincipal->GetURI(getter_AddRefs(uri));
   1.796 +  NS_ENSURE_TRUE(uri, false);
   1.797 +
   1.798 +  bool isChrome = false;
   1.799 +  return NS_SUCCEEDED(uri->SchemeIs("chrome", &isChrome)) && isChrome;
   1.800 +}
   1.801 +
   1.802 +nsresult
   1.803 +nsXBLService::LoadBindingDocumentInfo(nsIContent* aBoundElement,
   1.804 +                                      nsIDocument* aBoundDocument,
   1.805 +                                      nsIURI* aBindingURI,
   1.806 +                                      nsIPrincipal* aOriginPrincipal,
   1.807 +                                      bool aForceSyncLoad,
   1.808 +                                      nsXBLDocumentInfo** aResult)
   1.809 +{
   1.810 +  NS_PRECONDITION(aBindingURI, "Must have a binding URI");
   1.811 +  NS_PRECONDITION(!aOriginPrincipal || aBoundDocument,
   1.812 +                  "If we're doing a security check, we better have a document!");
   1.813 +
   1.814 +  nsresult rv;
   1.815 +  if (aOriginPrincipal) {
   1.816 +    // Security check - Enforce same-origin policy, except to chrome.
   1.817 +    // We have to be careful to not pass aContent as the context here.
   1.818 +    // Otherwise, if there is a JS-implemented content policy, we will attempt
   1.819 +    // to wrap the content node, which will try to load XBL bindings for it, if
   1.820 +    // any. Since we're not done loading this binding yet, that will reenter
   1.821 +    // this method and we'll end up creating a binding and then immediately
   1.822 +    // clobbering it in our table.  That makes things very confused, leading to
   1.823 +    // misbehavior and crashes.
   1.824 +    rv = nsContentUtils::
   1.825 +      CheckSecurityBeforeLoad(aBindingURI, aOriginPrincipal,
   1.826 +                              nsIScriptSecurityManager::ALLOW_CHROME,
   1.827 +                              gAllowDataURIs,
   1.828 +                              nsIContentPolicy::TYPE_XBL,
   1.829 +                              aBoundDocument);
   1.830 +    NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
   1.831 +
   1.832 +    if (!IsSystemOrChromeURLPrincipal(aOriginPrincipal)) {
   1.833 +      // Also make sure that we're same-origin with the bound document
   1.834 +      // except if the stylesheet has the system principal.
   1.835 +      if (!(gAllowDataURIs && SchemeIs(aBindingURI, "data")) &&
   1.836 +          !SchemeIs(aBindingURI, "chrome")) {
   1.837 +        rv = aBoundDocument->NodePrincipal()->CheckMayLoad(aBindingURI,
   1.838 +                                                           true, false);
   1.839 +        NS_ENSURE_SUCCESS(rv, NS_ERROR_XBL_BLOCKED);
   1.840 +      }
   1.841 +
   1.842 +      // Finally check if this document is allowed to use XBL at all.
   1.843 +      NS_ENSURE_TRUE(aBoundDocument->AllowXULXBL(),
   1.844 +                     NS_ERROR_XBL_BLOCKED);
   1.845 +    }
   1.846 +  }
   1.847 +
   1.848 +  *aResult = nullptr;
   1.849 +  nsRefPtr<nsXBLDocumentInfo> info;
   1.850 +
   1.851 +  nsCOMPtr<nsIURI> documentURI;
   1.852 +  rv = aBindingURI->CloneIgnoringRef(getter_AddRefs(documentURI));
   1.853 +  NS_ENSURE_SUCCESS(rv, rv);
   1.854 +
   1.855 +#ifdef MOZ_XUL
   1.856 +  // We've got a file.  Check our XBL document cache.
   1.857 +  nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
   1.858 +  bool useXULCache = cache && cache->IsEnabled();
   1.859 +
   1.860 +  if (useXULCache) {
   1.861 +    // The first line of defense is the chrome cache.
   1.862 +    // This cache crosses the entire product, so that any XBL bindings that are
   1.863 +    // part of chrome will be reused across all XUL documents.
   1.864 +    info = cache->GetXBLDocumentInfo(documentURI);
   1.865 +  }
   1.866 +#endif
   1.867 +
   1.868 +  if (!info) {
   1.869 +    // The second line of defense is the binding manager's document table.
   1.870 +    nsBindingManager *bindingManager = nullptr;
   1.871 +
   1.872 +    if (aBoundDocument) {
   1.873 +      bindingManager = aBoundDocument->BindingManager();
   1.874 +      info = bindingManager->GetXBLDocumentInfo(documentURI);
   1.875 +      if (aBoundDocument->IsStaticDocument() &&
   1.876 +          IsChromeOrResourceURI(aBindingURI)) {
   1.877 +        aForceSyncLoad = true;
   1.878 +      }
   1.879 +    }
   1.880 +
   1.881 +    nsINodeInfo *ni = nullptr;
   1.882 +    if (aBoundElement)
   1.883 +      ni = aBoundElement->NodeInfo();
   1.884 +
   1.885 +    if (!info && bindingManager &&
   1.886 +        (!ni || !(ni->Equals(nsGkAtoms::scrollbar, kNameSpaceID_XUL) ||
   1.887 +                  ni->Equals(nsGkAtoms::thumb, kNameSpaceID_XUL) ||
   1.888 +                  ((ni->Equals(nsGkAtoms::input) ||
   1.889 +                    ni->Equals(nsGkAtoms::select)) &&
   1.890 +                   aBoundElement->IsHTML()))) && !aForceSyncLoad) {
   1.891 +      // The third line of defense is to investigate whether or not the
   1.892 +      // document is currently being loaded asynchronously.  If so, there's no
   1.893 +      // document yet, but we need to glom on our request so that it will be
   1.894 +      // processed whenever the doc does finish loading.
   1.895 +      nsCOMPtr<nsIStreamListener> listener;
   1.896 +      if (bindingManager)
   1.897 +        listener = bindingManager->GetLoadingDocListener(documentURI);
   1.898 +      if (listener) {
   1.899 +        nsXBLStreamListener* xblListener =
   1.900 +          static_cast<nsXBLStreamListener*>(listener.get());
   1.901 +        // Create a new load observer.
   1.902 +        if (!xblListener->HasRequest(aBindingURI, aBoundElement)) {
   1.903 +          nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI, aBoundElement);
   1.904 +          xblListener->AddRequest(req);
   1.905 +        }
   1.906 +        return NS_OK;
   1.907 +      }
   1.908 +    }
   1.909 +
   1.910 +#ifdef MOZ_XUL
   1.911 +    // Next, look in the startup cache
   1.912 +    bool useStartupCache = useXULCache && IsChromeOrResourceURI(documentURI);
   1.913 +    if (!info && useStartupCache) {
   1.914 +      rv = nsXBLDocumentInfo::ReadPrototypeBindings(documentURI, getter_AddRefs(info));
   1.915 +      if (NS_SUCCEEDED(rv)) {
   1.916 +        cache->PutXBLDocumentInfo(info);
   1.917 +
   1.918 +        if (bindingManager) {
   1.919 +          // Cache it in our binding manager's document table.
   1.920 +          bindingManager->PutXBLDocumentInfo(info);
   1.921 +        }
   1.922 +      }
   1.923 +    }
   1.924 +#endif
   1.925 +
   1.926 +    if (!info) {
   1.927 +      // Finally, if all lines of defense fail, we go and fetch the binding
   1.928 +      // document.
   1.929 +
   1.930 +      // Always load chrome synchronously
   1.931 +      bool chrome;
   1.932 +      if (NS_SUCCEEDED(documentURI->SchemeIs("chrome", &chrome)) && chrome)
   1.933 +        aForceSyncLoad = true;
   1.934 +
   1.935 +      nsCOMPtr<nsIDocument> document;
   1.936 +      FetchBindingDocument(aBoundElement, aBoundDocument, documentURI,
   1.937 +                           aBindingURI, aForceSyncLoad, getter_AddRefs(document));
   1.938 +
   1.939 +      if (document) {
   1.940 +        nsBindingManager *xblDocBindingManager = document->BindingManager();
   1.941 +        info = xblDocBindingManager->GetXBLDocumentInfo(documentURI);
   1.942 +        if (!info) {
   1.943 +          NS_ERROR("An XBL file is malformed.  Did you forget the XBL namespace on the bindings tag?");
   1.944 +          return NS_ERROR_FAILURE;
   1.945 +        }
   1.946 +        xblDocBindingManager->RemoveXBLDocumentInfo(info); // Break the self-imposed cycle.
   1.947 +
   1.948 +        // If the doc is a chrome URI, then we put it into the XUL cache.
   1.949 +#ifdef MOZ_XUL
   1.950 +        if (useStartupCache) {
   1.951 +          cache->PutXBLDocumentInfo(info);
   1.952 +
   1.953 +          // now write the bindings into the startup cache
   1.954 +          info->WritePrototypeBindings();
   1.955 +        }
   1.956 +#endif
   1.957 +
   1.958 +        if (bindingManager) {
   1.959 +          // Also put it in our binding manager's document table.
   1.960 +          bindingManager->PutXBLDocumentInfo(info);
   1.961 +        }
   1.962 +      }
   1.963 +    }
   1.964 +  }
   1.965 +
   1.966 +  info.forget(aResult);
   1.967 +
   1.968 +  return NS_OK;
   1.969 +}
   1.970 +
   1.971 +nsresult
   1.972 +nsXBLService::FetchBindingDocument(nsIContent* aBoundElement, nsIDocument* aBoundDocument,
   1.973 +                                   nsIURI* aDocumentURI, nsIURI* aBindingURI,
   1.974 +                                   bool aForceSyncLoad, nsIDocument** aResult)
   1.975 +{
   1.976 +  nsresult rv = NS_OK;
   1.977 +  // Initialize our out pointer to nullptr
   1.978 +  *aResult = nullptr;
   1.979 +
   1.980 +  // Now we have to synchronously load the binding file.
   1.981 +  // Create an XML content sink and a parser.
   1.982 +  nsCOMPtr<nsILoadGroup> loadGroup;
   1.983 +  if (aBoundDocument)
   1.984 +    loadGroup = aBoundDocument->GetDocumentLoadGroup();
   1.985 +
   1.986 +  // We really shouldn't have to force a sync load for anything here... could
   1.987 +  // we get away with not doing that?  Not sure.
   1.988 +  if (IsChromeOrResourceURI(aDocumentURI))
   1.989 +    aForceSyncLoad = true;
   1.990 +
   1.991 +  // Create document and contentsink and set them up.
   1.992 +  nsCOMPtr<nsIDocument> doc;
   1.993 +  rv = NS_NewXMLDocument(getter_AddRefs(doc));
   1.994 +  NS_ENSURE_SUCCESS(rv, rv);
   1.995 +
   1.996 +  nsCOMPtr<nsIXMLContentSink> xblSink;
   1.997 +  rv = NS_NewXBLContentSink(getter_AddRefs(xblSink), doc, aDocumentURI, nullptr);
   1.998 +  NS_ENSURE_SUCCESS(rv, rv);
   1.999 +
  1.1000 +  // Open channel
  1.1001 +  nsCOMPtr<nsIChannel> channel;
  1.1002 +  rv = NS_NewChannel(getter_AddRefs(channel), aDocumentURI, nullptr, loadGroup);
  1.1003 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1004 +
  1.1005 +  nsCOMPtr<nsIInterfaceRequestor> sameOriginChecker = nsContentUtils::GetSameOriginChecker();
  1.1006 +  NS_ENSURE_TRUE(sameOriginChecker, NS_ERROR_OUT_OF_MEMORY);
  1.1007 +
  1.1008 +  channel->SetNotificationCallbacks(sameOriginChecker);
  1.1009 +
  1.1010 +  if (!aForceSyncLoad) {
  1.1011 +    // We can be asynchronous
  1.1012 +    nsXBLStreamListener* xblListener =
  1.1013 +      new nsXBLStreamListener(aBoundDocument, xblSink, doc);
  1.1014 +    NS_ENSURE_TRUE(xblListener,NS_ERROR_OUT_OF_MEMORY);
  1.1015 +
  1.1016 +    // Add ourselves to the list of loading docs.
  1.1017 +    nsBindingManager *bindingManager;
  1.1018 +    if (aBoundDocument)
  1.1019 +      bindingManager = aBoundDocument->BindingManager();
  1.1020 +    else
  1.1021 +      bindingManager = nullptr;
  1.1022 +
  1.1023 +    if (bindingManager)
  1.1024 +      bindingManager->PutLoadingDocListener(aDocumentURI, xblListener);
  1.1025 +
  1.1026 +    // Add our request.
  1.1027 +    nsXBLBindingRequest* req = new nsXBLBindingRequest(aBindingURI,
  1.1028 +                                                       aBoundElement);
  1.1029 +    xblListener->AddRequest(req);
  1.1030 +
  1.1031 +    // Now kick off the async read.
  1.1032 +    rv = channel->AsyncOpen(xblListener, nullptr);
  1.1033 +    if (NS_FAILED(rv)) {
  1.1034 +      // Well, we won't be getting a load.  Make sure to clean up our stuff!
  1.1035 +      if (bindingManager) {
  1.1036 +        bindingManager->RemoveLoadingDocListener(aDocumentURI);
  1.1037 +      }
  1.1038 +    }
  1.1039 +    return NS_OK;
  1.1040 +  }
  1.1041 +
  1.1042 +  nsCOMPtr<nsIStreamListener> listener;
  1.1043 +  rv = doc->StartDocumentLoad("loadAsInteractiveData",
  1.1044 +                              channel,
  1.1045 +                              loadGroup,
  1.1046 +                              nullptr,
  1.1047 +                              getter_AddRefs(listener),
  1.1048 +                              true,
  1.1049 +                              xblSink);
  1.1050 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1051 +
  1.1052 +  // Now do a blocking synchronous parse of the file.
  1.1053 +  nsCOMPtr<nsIInputStream> in;
  1.1054 +  rv = channel->Open(getter_AddRefs(in));
  1.1055 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1056 +
  1.1057 +  rv = nsSyncLoadService::PushSyncStreamToListener(in, listener, channel);
  1.1058 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1059 +
  1.1060 +  doc.swap(*aResult);
  1.1061 +
  1.1062 +  return NS_OK;
  1.1063 +}

mercurial