LCOV - code coverage report
Current view: top level - dom/base - nsReferencedElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 43 123 35.0 %
Date: 2017-07-14 16:53:18 Functions: 3 13 23.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsReferencedElement.h"
       8             : #include "nsContentUtils.h"
       9             : #include "nsIURI.h"
      10             : #include "nsBindingManager.h"
      11             : #include "nsEscape.h"
      12             : #include "nsXBLPrototypeBinding.h"
      13             : #include "nsIDOMNode.h"
      14             : #include "nsIDOMElement.h"
      15             : #include "nsCycleCollectionParticipant.h"
      16             : 
      17             : void
      18          26 : nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
      19             :                            bool aWatch, bool aReferenceImage)
      20             : {
      21          26 :   MOZ_ASSERT(aFromContent, "Reset() expects non-null content pointer");
      22             : 
      23          26 :   Unlink();
      24             : 
      25          26 :   if (!aURI)
      26           2 :     return;
      27             : 
      28          50 :   nsAutoCString refPart;
      29          25 :   aURI->GetRef(refPart);
      30             :   // Unescape %-escapes in the reference. The result will be in the
      31             :   // origin charset of the URL, hopefully...
      32          25 :   NS_UnescapeURL(refPart);
      33             : 
      34          50 :   nsAutoCString charset;
      35          25 :   aURI->GetOriginCharset(charset);
      36          25 :   auto encoding = Encoding::ForLabelNoReplacement(charset);
      37          25 :   if (!encoding) {
      38           0 :     encoding = UTF_8_ENCODING;
      39             :   }
      40          50 :   nsAutoString ref;
      41          25 :   nsresult rv = encoding->DecodeWithoutBOMHandling(refPart, ref);
      42          25 :   if (NS_FAILED(rv) || ref.IsEmpty()) {
      43           0 :     return;
      44             :   }
      45          25 :   rv = NS_OK;
      46             : 
      47             :   // Get the current document
      48          25 :   nsIDocument *doc = aFromContent->OwnerDoc();
      49          25 :   if (!doc)
      50           0 :     return;
      51             : 
      52          25 :   nsIContent* bindingParent = aFromContent->GetBindingParent();
      53          25 :   if (bindingParent) {
      54           0 :     nsXBLBinding* binding = bindingParent->GetXBLBinding();
      55           0 :     if (!binding) {
      56             :       // This happens, for example, if aFromContent is part of the content
      57             :       // inserted by a call to nsIDocument::InsertAnonymousContent, which we
      58             :       // also want to handle.  (It also happens for <use>'s anonymous
      59             :       // content etc.)
      60             :       Element* anonRoot =
      61           0 :         doc->GetAnonRootIfInAnonymousContentContainer(aFromContent);
      62           0 :       if (anonRoot) {
      63           0 :         mElement = nsContentUtils::MatchElementId(anonRoot, ref);
      64             :         // We don't have watching working yet for anonymous content, so bail out here.
      65           0 :         return;
      66             :       }
      67             :     } else {
      68             :       bool isEqualExceptRef;
      69           0 :       rv = aURI->EqualsExceptRef(binding->PrototypeBinding()->DocURI(),
      70           0 :                                  &isEqualExceptRef);
      71           0 :       if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
      72             :         // XXX sXBL/XBL2 issue
      73             :         // Our content is an anonymous XBL element from a binding inside the
      74             :         // same document that the referenced URI points to. In order to avoid
      75             :         // the risk of ID collisions we restrict ourselves to anonymous
      76             :         // elements from this binding; specifically, URIs that are relative to
      77             :         // the binding document should resolve to the copy of the target
      78             :         // element that has been inserted into the bound document.
      79             :         // If the URI points to a different document we don't need this
      80             :         // restriction.
      81             :         nsINodeList* anonymousChildren =
      82           0 :           doc->BindingManager()->GetAnonymousNodesFor(bindingParent);
      83             : 
      84           0 :         if (anonymousChildren) {
      85             :           uint32_t length;
      86           0 :           anonymousChildren->GetLength(&length);
      87           0 :           for (uint32_t i = 0; i < length && !mElement; ++i) {
      88             :             mElement =
      89           0 :               nsContentUtils::MatchElementId(anonymousChildren->Item(i), ref);
      90             :           }
      91             :         }
      92             : 
      93             :         // We don't have watching working yet for XBL, so bail out here.
      94           0 :         return;
      95             :       }
      96             :     }
      97             :   }
      98             : 
      99             :   bool isEqualExceptRef;
     100          25 :   rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef);
     101          25 :   if (NS_FAILED(rv) || !isEqualExceptRef) {
     102           0 :     RefPtr<nsIDocument::ExternalResourceLoad> load;
     103           0 :     doc = doc->RequestExternalResource(aURI, aFromContent,
     104           0 :                                        getter_AddRefs(load));
     105           0 :     if (!doc) {
     106           0 :       if (!load || !aWatch) {
     107             :         // Nothing will ever happen here
     108           0 :         return;
     109             :       }
     110             : 
     111             :       DocumentLoadNotification* observer =
     112           0 :         new DocumentLoadNotification(this, ref);
     113           0 :       mPendingNotification = observer;
     114           0 :       if (observer) {
     115           0 :         load->AddObserver(observer);
     116             :       }
     117             :       // Keep going so we set up our watching stuff a bit
     118             :     }
     119             :   }
     120             : 
     121          25 :   if (aWatch) {
     122          50 :     nsCOMPtr<nsIAtom> atom = NS_Atomize(ref);
     123          25 :     if (!atom)
     124           0 :       return;
     125          25 :     atom.swap(mWatchID);
     126             :   }
     127             : 
     128          25 :   mReferencingImage = aReferenceImage;
     129             : 
     130          25 :   HaveNewDocument(doc, aWatch, ref);
     131             : }
     132             : 
     133             : void
     134           0 : nsReferencedElement::ResetWithID(nsIContent* aFromContent, const nsString& aID,
     135             :                                  bool aWatch)
     136             : {
     137           0 :   nsIDocument *doc = aFromContent->OwnerDoc();
     138           0 :   if (!doc)
     139           0 :     return;
     140             : 
     141             :   // XXX Need to take care of XBL/XBL2
     142             : 
     143           0 :   if (aWatch) {
     144           0 :     nsCOMPtr<nsIAtom> atom = NS_Atomize(aID);
     145           0 :     if (!atom)
     146           0 :       return;
     147           0 :     atom.swap(mWatchID);
     148             :   }
     149             : 
     150           0 :   mReferencingImage = false;
     151             : 
     152           0 :   HaveNewDocument(doc, aWatch, aID);
     153             : }
     154             : 
     155             : void
     156          25 : nsReferencedElement::HaveNewDocument(nsIDocument* aDocument, bool aWatch,
     157             :                                      const nsString& aRef)
     158             : {
     159          25 :   if (aWatch) {
     160          25 :     mWatchDocument = aDocument;
     161          25 :     if (mWatchDocument) {
     162          25 :       mElement = mWatchDocument->AddIDTargetObserver(mWatchID, Observe, this,
     163          25 :                                                      mReferencingImage);
     164             :     }
     165          25 :     return;
     166             :   }
     167             : 
     168           0 :   if (!aDocument) {
     169           0 :     return;
     170             :   }
     171             : 
     172           0 :   Element *e = mReferencingImage ? aDocument->LookupImageElement(aRef) :
     173           0 :                                    aDocument->GetElementById(aRef);
     174           0 :   if (e) {
     175           0 :     mElement = e;
     176             :   }
     177             : }
     178             : 
     179             : void
     180           0 : nsReferencedElement::Traverse(nsCycleCollectionTraversalCallback* aCB)
     181             : {
     182           0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mWatchDocument");
     183           0 :   aCB->NoteXPCOMChild(mWatchDocument);
     184           0 :   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mContent");
     185           0 :   aCB->NoteXPCOMChild(mElement);
     186           0 : }
     187             : 
     188             : void
     189          26 : nsReferencedElement::Unlink()
     190             : {
     191          26 :   if (mWatchDocument && mWatchID) {
     192           0 :     mWatchDocument->RemoveIDTargetObserver(mWatchID, Observe, this,
     193           0 :                                            mReferencingImage);
     194             :   }
     195          26 :   if (mPendingNotification) {
     196           0 :     mPendingNotification->Clear();
     197           0 :     mPendingNotification = nullptr;
     198             :   }
     199          26 :   mWatchDocument = nullptr;
     200          26 :   mWatchID = nullptr;
     201          26 :   mElement = nullptr;
     202          26 :   mReferencingImage = false;
     203          26 : }
     204             : 
     205             : bool
     206           0 : nsReferencedElement::Observe(Element* aOldElement,
     207             :                              Element* aNewElement, void* aData)
     208             : {
     209           0 :   nsReferencedElement* p = static_cast<nsReferencedElement*>(aData);
     210           0 :   if (p->mPendingNotification) {
     211           0 :     p->mPendingNotification->SetTo(aNewElement);
     212             :   } else {
     213           0 :     NS_ASSERTION(aOldElement == p->mElement, "Failed to track content!");
     214             :     ChangeNotification* watcher =
     215           0 :       new ChangeNotification(p, aOldElement, aNewElement);
     216           0 :     p->mPendingNotification = watcher;
     217           0 :     nsContentUtils::AddScriptRunner(watcher);
     218             :   }
     219           0 :   bool keepTracking = p->IsPersistent();
     220           0 :   if (!keepTracking) {
     221           0 :     p->mWatchDocument = nullptr;
     222           0 :     p->mWatchID = nullptr;
     223             :   }
     224           0 :   return keepTracking;
     225             : }
     226             : 
     227           0 : NS_IMPL_ISUPPORTS_INHERITED0(nsReferencedElement::ChangeNotification,
     228             :                              mozilla::Runnable)
     229             : 
     230           0 : NS_IMPL_ISUPPORTS(nsReferencedElement::DocumentLoadNotification,
     231             :                   nsIObserver)
     232             : 
     233             : NS_IMETHODIMP
     234           0 : nsReferencedElement::DocumentLoadNotification::Observe(nsISupports* aSubject,
     235             :                                                        const char* aTopic,
     236             :                                                        const char16_t* aData)
     237             : {
     238           0 :   NS_ASSERTION(PL_strcmp(aTopic, "external-resource-document-created") == 0,
     239             :                "Unexpected topic");
     240           0 :   if (mTarget) {
     241           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
     242           0 :     mTarget->mPendingNotification = nullptr;
     243           0 :     NS_ASSERTION(!mTarget->mElement, "Why do we have content here?");
     244             :     // If we got here, that means we had Reset() called with aWatch ==
     245             :     // true.  So keep watching if IsPersistent().
     246           0 :     mTarget->HaveNewDocument(doc, mTarget->IsPersistent(), mRef);
     247           0 :     mTarget->ElementChanged(nullptr, mTarget->mElement);
     248             :   }
     249           0 :   return NS_OK;
     250             : }

Generated by: LCOV version 1.13