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.)

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

mercurial