content/base/src/nsReferencedElement.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 sw=2 et tw=78: */
     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/. */
     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"
    17 void
    18 nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI,
    19                            bool aWatch, bool aReferenceImage)
    20 {
    21   NS_ABORT_IF_FALSE(aFromContent, "Reset() expects non-null content pointer");
    23   Unlink();
    25   if (!aURI)
    26     return;
    28   nsAutoCString refPart;
    29   aURI->GetRef(refPart);
    30   // Unescape %-escapes in the reference. The result will be in the
    31   // origin charset of the URL, hopefully...
    32   NS_UnescapeURL(refPart);
    34   nsAutoCString charset;
    35   aURI->GetOriginCharset(charset);
    36   nsAutoString ref;
    37   nsresult rv = nsContentUtils::ConvertStringFromEncoding(charset,
    38                                                           refPart,
    39                                                           ref);
    40   if (NS_FAILED(rv)) {
    41     // XXX Eww. If fallible malloc failed, using a conversion method that
    42     // assumes UTF-8 and doesn't handle UTF-8 errors.
    43     // https://bugzilla.mozilla.org/show_bug.cgi?id=951082
    44     CopyUTF8toUTF16(refPart, ref);
    45   }
    46   if (ref.IsEmpty())
    47     return;
    49   // Get the current document
    50   nsIDocument *doc = aFromContent->GetCurrentDoc();
    51   if (!doc)
    52     return;
    54   nsIContent* bindingParent = aFromContent->GetBindingParent();
    55   if (bindingParent) {
    56     nsXBLBinding* binding = bindingParent->GetXBLBinding();
    57     if (binding) {
    58       bool isEqualExceptRef;
    59       rv = aURI->EqualsExceptRef(binding->PrototypeBinding()->DocURI(),
    60                                  &isEqualExceptRef);
    61       if (NS_SUCCEEDED(rv) && isEqualExceptRef) {
    62         // XXX sXBL/XBL2 issue
    63         // Our content is an anonymous XBL element from a binding inside the
    64         // same document that the referenced URI points to. In order to avoid
    65         // the risk of ID collisions we restrict ourselves to anonymous
    66         // elements from this binding; specifically, URIs that are relative to
    67         // the binding document should resolve to the copy of the target
    68         // element that has been inserted into the bound document.
    69         // If the URI points to a different document we don't need this
    70         // restriction.
    71         nsINodeList* anonymousChildren =
    72           doc->BindingManager()->GetAnonymousNodesFor(bindingParent);
    74         if (anonymousChildren) {
    75           uint32_t length;
    76           anonymousChildren->GetLength(&length);
    77           for (uint32_t i = 0; i < length && !mElement; ++i) {
    78             mElement =
    79               nsContentUtils::MatchElementId(anonymousChildren->Item(i), ref);
    80           }
    81         }
    83         // We don't have watching working yet for XBL, so bail out here.
    84         return;
    85       }
    86     }
    87   }
    89   bool isEqualExceptRef;
    90   rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef);
    91   if (NS_FAILED(rv) || !isEqualExceptRef) {
    92     nsRefPtr<nsIDocument::ExternalResourceLoad> load;
    93     doc = doc->RequestExternalResource(aURI, aFromContent,
    94                                        getter_AddRefs(load));
    95     if (!doc) {
    96       if (!load || !aWatch) {
    97         // Nothing will ever happen here
    98         return;
    99       }
   101       DocumentLoadNotification* observer =
   102         new DocumentLoadNotification(this, ref);
   103       mPendingNotification = observer;
   104       if (observer) {
   105         load->AddObserver(observer);
   106       }
   107       // Keep going so we set up our watching stuff a bit
   108     }
   109   }
   111   if (aWatch) {
   112     nsCOMPtr<nsIAtom> atom = do_GetAtom(ref);
   113     if (!atom)
   114       return;
   115     atom.swap(mWatchID);
   116   }
   118   mReferencingImage = aReferenceImage;
   120   HaveNewDocument(doc, aWatch, ref);
   121 }
   123 void
   124 nsReferencedElement::ResetWithID(nsIContent* aFromContent, const nsString& aID,
   125                                  bool aWatch)
   126 {
   127   nsIDocument *doc = aFromContent->GetCurrentDoc();
   128   if (!doc)
   129     return;
   131   // XXX Need to take care of XBL/XBL2
   133   if (aWatch) {
   134     nsCOMPtr<nsIAtom> atom = do_GetAtom(aID);
   135     if (!atom)
   136       return;
   137     atom.swap(mWatchID);
   138   }
   140   mReferencingImage = false;
   142   HaveNewDocument(doc, aWatch, aID);
   143 }
   145 void
   146 nsReferencedElement::HaveNewDocument(nsIDocument* aDocument, bool aWatch,
   147                                      const nsString& aRef)
   148 {
   149   if (aWatch) {
   150     mWatchDocument = aDocument;
   151     if (mWatchDocument) {
   152       mElement = mWatchDocument->AddIDTargetObserver(mWatchID, Observe, this,
   153                                                      mReferencingImage);
   154     }
   155     return;
   156   }
   158   if (!aDocument) {
   159     return;
   160   }
   162   Element *e = mReferencingImage ? aDocument->LookupImageElement(aRef) :
   163                                    aDocument->GetElementById(aRef);
   164   if (e) {
   165     mElement = e;
   166   }
   167 }
   169 void
   170 nsReferencedElement::Traverse(nsCycleCollectionTraversalCallback* aCB)
   171 {
   172   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mWatchDocument");
   173   aCB->NoteXPCOMChild(mWatchDocument);
   174   NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCB, "mContent");
   175   aCB->NoteXPCOMChild(mElement);
   176 }
   178 void
   179 nsReferencedElement::Unlink()
   180 {
   181   if (mWatchDocument && mWatchID) {
   182     mWatchDocument->RemoveIDTargetObserver(mWatchID, Observe, this,
   183                                            mReferencingImage);
   184   }
   185   if (mPendingNotification) {
   186     mPendingNotification->Clear();
   187     mPendingNotification = nullptr;
   188   }
   189   mWatchDocument = nullptr;
   190   mWatchID = nullptr;
   191   mElement = nullptr;
   192   mReferencingImage = false;
   193 }
   195 bool
   196 nsReferencedElement::Observe(Element* aOldElement,
   197                              Element* aNewElement, void* aData)
   198 {
   199   nsReferencedElement* p = static_cast<nsReferencedElement*>(aData);
   200   if (p->mPendingNotification) {
   201     p->mPendingNotification->SetTo(aNewElement);
   202   } else {
   203     NS_ASSERTION(aOldElement == p->mElement, "Failed to track content!");
   204     ChangeNotification* watcher =
   205       new ChangeNotification(p, aOldElement, aNewElement);
   206     p->mPendingNotification = watcher;
   207     nsContentUtils::AddScriptRunner(watcher);
   208   }
   209   bool keepTracking = p->IsPersistent();
   210   if (!keepTracking) {
   211     p->mWatchDocument = nullptr;
   212     p->mWatchID = nullptr;
   213   }
   214   return keepTracking;
   215 }
   217 NS_IMPL_ISUPPORTS_INHERITED0(nsReferencedElement::ChangeNotification,
   218                              nsRunnable)
   220 NS_IMPL_ISUPPORTS(nsReferencedElement::DocumentLoadNotification,
   221                   nsIObserver)
   223 NS_IMETHODIMP
   224 nsReferencedElement::DocumentLoadNotification::Observe(nsISupports* aSubject,
   225                                                        const char* aTopic,
   226                                                        const char16_t* aData)
   227 {
   228   NS_ASSERTION(PL_strcmp(aTopic, "external-resource-document-created") == 0,
   229                "Unexpected topic");
   230   if (mTarget) {
   231     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aSubject);
   232     mTarget->mPendingNotification = nullptr;
   233     NS_ASSERTION(!mTarget->mElement, "Why do we have content here?");
   234     // If we got here, that means we had Reset() called with aWatch ==
   235     // true.  So keep watching if IsPersistent().
   236     mTarget->HaveNewDocument(doc, mTarget->IsPersistent(), mRef);
   237     mTarget->ElementChanged(nullptr, mTarget->mElement);
   238   }
   239   return NS_OK;
   240 }

mercurial