content/base/src/Link.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: sw=2 ts=2 et :
     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 "Link.h"
     9 #include "mozilla/EventStates.h"
    10 #include "mozilla/MemoryReporting.h"
    11 #include "mozilla/dom/Element.h"
    12 #include "nsIURL.h"
    13 #include "nsISizeOf.h"
    15 #include "nsEscape.h"
    16 #include "nsGkAtoms.h"
    17 #include "nsString.h"
    18 #include "mozAutoDocUpdate.h"
    20 #include "mozilla/Services.h"
    22 namespace mozilla {
    23 namespace dom {
    25 Link::Link(Element *aElement)
    26   : mElement(aElement)
    27   , mHistory(services::GetHistoryService())
    28   , mLinkState(eLinkState_NotLink)
    29   , mNeedsRegistration(false)
    30   , mRegistered(false)
    31 {
    32   NS_ABORT_IF_FALSE(mElement, "Must have an element");
    33 }
    35 Link::~Link()
    36 {
    37   UnregisterFromHistory();
    38 }
    40 bool
    41 Link::ElementHasHref() const
    42 {
    43   return ((!mElement->IsSVG() && mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href))
    44         || (!mElement->IsHTML() && mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href)));
    45 }
    47 void
    48 Link::SetLinkState(nsLinkState aState)
    49 {
    50   NS_ASSERTION(mRegistered,
    51                "Setting the link state of an unregistered Link!");
    52   NS_ASSERTION(mLinkState != aState,
    53                "Setting state to the currently set state!");
    55   // Set our current state as appropriate.
    56   mLinkState = aState;
    58   // Per IHistory interface documentation, we are no longer registered.
    59   mRegistered = false;
    61   NS_ABORT_IF_FALSE(LinkState() == NS_EVENT_STATE_VISITED ||
    62                     LinkState() == NS_EVENT_STATE_UNVISITED,
    63                     "Unexpected state obtained from LinkState()!");
    65   // Tell the element to update its visited state
    66   mElement->UpdateState(true);
    67 }
    69 EventStates
    70 Link::LinkState() const
    71 {
    72   // We are a constant method, but we are just lazily doing things and have to
    73   // track that state.  Cast away that constness!
    74   Link *self = const_cast<Link *>(this);
    76   Element *element = self->mElement;
    78   // If we have not yet registered for notifications and need to,
    79   // due to our href changing, register now!
    80   if (!mRegistered && mNeedsRegistration && element->IsInDoc()) {
    81     // Only try and register once.
    82     self->mNeedsRegistration = false;
    84     nsCOMPtr<nsIURI> hrefURI(GetURI());
    86     // Assume that we are not visited until we are told otherwise.
    87     self->mLinkState = eLinkState_Unvisited;
    89     // Make sure the href attribute has a valid link (bug 23209).
    90     // If we have a good href, register with History if available.
    91     if (mHistory && hrefURI) {
    92       nsresult rv = mHistory->RegisterVisitedCallback(hrefURI, self);
    93       if (NS_SUCCEEDED(rv)) {
    94         self->mRegistered = true;
    96         // And make sure we are in the document's link map.
    97         element->GetCurrentDoc()->AddStyleRelevantLink(self);
    98       }
    99     }
   100   }
   102   // Otherwise, return our known state.
   103   if (mLinkState == eLinkState_Visited) {
   104     return NS_EVENT_STATE_VISITED;
   105   }
   107   if (mLinkState == eLinkState_Unvisited) {
   108     return NS_EVENT_STATE_UNVISITED;
   109   }
   111   return EventStates();
   112 }
   114 nsIURI*
   115 Link::GetURI() const
   116 {
   117   // If we have this URI cached, use it.
   118   if (mCachedURI) {
   119     return mCachedURI;
   120   }
   122   // Otherwise obtain it.
   123   Link *self = const_cast<Link *>(this);
   124   Element *element = self->mElement;
   125   mCachedURI = element->GetHrefURI();
   127   return mCachedURI;
   128 }
   130 void
   131 Link::SetProtocol(const nsAString &aProtocol)
   132 {
   133   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   134   if (!uri) {
   135     // Ignore failures to be compatible with NS4.
   136     return;
   137   }
   139   nsAString::const_iterator start, end;
   140   aProtocol.BeginReading(start);
   141   aProtocol.EndReading(end);
   142   nsAString::const_iterator iter(start);
   143   (void)FindCharInReadable(':', iter, end);
   144   (void)uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
   146   SetHrefAttribute(uri);
   147 }
   149 void
   150 Link::SetPassword(const nsAString &aPassword)
   151 {
   152   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   153   if (!uri) {
   154     // Ignore failures to be compatible with NS4.
   155     return;
   156   }
   158   uri->SetPassword(NS_ConvertUTF16toUTF8(aPassword));
   159   SetHrefAttribute(uri);
   160 }
   162 void
   163 Link::SetUsername(const nsAString &aUsername)
   164 {
   165   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   166   if (!uri) {
   167     // Ignore failures to be compatible with NS4.
   168     return;
   169   }
   171   uri->SetUsername(NS_ConvertUTF16toUTF8(aUsername));
   172   SetHrefAttribute(uri);
   173 }
   175 void
   176 Link::SetHost(const nsAString &aHost)
   177 {
   178   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   179   if (!uri) {
   180     // Ignore failures to be compatible with NS4.
   181     return;
   182   }
   184   (void)uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
   185   SetHrefAttribute(uri);
   186 }
   188 void
   189 Link::SetHostname(const nsAString &aHostname)
   190 {
   191   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   192   if (!uri) {
   193     // Ignore failures to be compatible with NS4.
   194     return;
   195   }
   197   (void)uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
   198   SetHrefAttribute(uri);
   199 }
   201 void
   202 Link::SetPathname(const nsAString &aPathname)
   203 {
   204   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   205   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   206   if (!url) {
   207     // Ignore failures to be compatible with NS4.
   208     return;
   209   }
   211   (void)url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
   212   SetHrefAttribute(uri);
   213 }
   215 void
   216 Link::SetSearch(const nsAString& aSearch)
   217 {
   218   SetSearchInternal(aSearch);
   219   UpdateURLSearchParams();
   220 }
   222 void
   223 Link::SetSearchInternal(const nsAString& aSearch)
   224 {
   225   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   226   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   227   if (!url) {
   228     // Ignore failures to be compatible with NS4.
   229     return;
   230   }
   232   (void)url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
   233   SetHrefAttribute(uri);
   234 }
   236 void
   237 Link::SetPort(const nsAString &aPort)
   238 {
   239   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   240   if (!uri) {
   241     // Ignore failures to be compatible with NS4.
   242     return;
   243   }
   245   nsresult rv;
   246   nsAutoString portStr(aPort);
   248   // nsIURI uses -1 as default value.
   249   int32_t port = -1;
   250   if (!aPort.IsEmpty()) {
   251     port = portStr.ToInteger(&rv);
   252     if (NS_FAILED(rv)) {
   253       return;
   254     }
   255   }
   257   (void)uri->SetPort(port);
   258   SetHrefAttribute(uri);
   259 }
   261 void
   262 Link::SetHash(const nsAString &aHash)
   263 {
   264   nsCOMPtr<nsIURI> uri(GetURIToMutate());
   265   if (!uri) {
   266     // Ignore failures to be compatible with NS4.
   267     return;
   268   }
   270   (void)uri->SetRef(NS_ConvertUTF16toUTF8(aHash));
   271   SetHrefAttribute(uri);
   272 }
   274 void
   275 Link::GetOrigin(nsAString &aOrigin)
   276 {
   277   aOrigin.Truncate();
   279   nsCOMPtr<nsIURI> uri(GetURI());
   280   if (!uri) {
   281     return;
   282   }
   284   nsString origin;
   285   nsContentUtils::GetUTFNonNullOrigin(uri, origin);
   286   aOrigin.Assign(origin);
   287 }
   289 void
   290 Link::GetProtocol(nsAString &_protocol)
   291 {
   292   nsCOMPtr<nsIURI> uri(GetURI());
   293   if (!uri) {
   294     _protocol.AssignLiteral("http");
   295   }
   296   else {
   297     nsAutoCString scheme;
   298     (void)uri->GetScheme(scheme);
   299     CopyASCIItoUTF16(scheme, _protocol);
   300   }
   301   _protocol.Append(char16_t(':'));
   302   return;
   303 }
   305 void
   306 Link::GetUsername(nsAString& aUsername)
   307 {
   308   aUsername.Truncate();
   310   nsCOMPtr<nsIURI> uri(GetURI());
   311   if (!uri) {
   312     return;
   313   }
   315   nsAutoCString username;
   316   uri->GetUsername(username);
   317   CopyASCIItoUTF16(username, aUsername);
   318 }
   320 void
   321 Link::GetPassword(nsAString &aPassword)
   322 {
   323   aPassword.Truncate();
   325   nsCOMPtr<nsIURI> uri(GetURI());
   326   if (!uri) {
   327     return;
   328   }
   330   nsAutoCString password;
   331   uri->GetPassword(password);
   332   CopyASCIItoUTF16(password, aPassword);
   333 }
   335 void
   336 Link::GetHost(nsAString &_host)
   337 {
   338   _host.Truncate();
   340   nsCOMPtr<nsIURI> uri(GetURI());
   341   if (!uri) {
   342     // Do not throw!  Not having a valid URI should result in an empty string.
   343     return;
   344   }
   346   nsAutoCString hostport;
   347   nsresult rv = uri->GetHostPort(hostport);
   348   if (NS_SUCCEEDED(rv)) {
   349     CopyUTF8toUTF16(hostport, _host);
   350   }
   351 }
   353 void
   354 Link::GetHostname(nsAString &_hostname)
   355 {
   356   _hostname.Truncate();
   358   nsCOMPtr<nsIURI> uri(GetURI());
   359   if (!uri) {
   360     // Do not throw!  Not having a valid URI should result in an empty string.
   361     return;
   362   }
   364   nsAutoCString host;
   365   nsresult rv = uri->GetHost(host);
   366   // Note that failure to get the host from the URI is not necessarily a bad
   367   // thing.  Some URIs do not have a host.
   368   if (NS_SUCCEEDED(rv)) {
   369     CopyUTF8toUTF16(host, _hostname);
   370   }
   371 }
   373 void
   374 Link::GetPathname(nsAString &_pathname)
   375 {
   376   _pathname.Truncate();
   378   nsCOMPtr<nsIURI> uri(GetURI());
   379   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   380   if (!url) {
   381     // Do not throw!  Not having a valid URI or URL should result in an empty
   382     // string.
   383     return;
   384   }
   386   nsAutoCString file;
   387   nsresult rv = url->GetFilePath(file);
   388   if (NS_SUCCEEDED(rv)) {
   389     CopyUTF8toUTF16(file, _pathname);
   390   }
   391 }
   393 void
   394 Link::GetSearch(nsAString &_search)
   395 {
   396   _search.Truncate();
   398   nsCOMPtr<nsIURI> uri(GetURI());
   399   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   400   if (!url) {
   401     // Do not throw!  Not having a valid URI or URL should result in an empty
   402     // string.
   403     return;
   404   }
   406   nsAutoCString search;
   407   nsresult rv = url->GetQuery(search);
   408   if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
   409     CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, _search);
   410   }
   411 }
   413 void
   414 Link::GetPort(nsAString &_port)
   415 {
   416   _port.Truncate();
   418   nsCOMPtr<nsIURI> uri(GetURI());
   419   if (!uri) {
   420     // Do not throw!  Not having a valid URI should result in an empty string.
   421     return;
   422   }
   424   int32_t port;
   425   nsresult rv = uri->GetPort(&port);
   426   // Note that failure to get the port from the URI is not necessarily a bad
   427   // thing.  Some URIs do not have a port.
   428   if (NS_SUCCEEDED(rv) && port != -1) {
   429     nsAutoString portStr;
   430     portStr.AppendInt(port, 10);
   431     _port.Assign(portStr);
   432   }
   433 }
   435 void
   436 Link::GetHash(nsAString &_hash)
   437 {
   438   _hash.Truncate();
   440   nsCOMPtr<nsIURI> uri(GetURI());
   441   if (!uri) {
   442     // Do not throw!  Not having a valid URI should result in an empty
   443     // string.
   444     return;
   445   }
   447   nsAutoCString ref;
   448   nsresult rv = uri->GetRef(ref);
   449   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
   450     NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
   451     _hash.Assign(char16_t('#'));
   452     AppendUTF8toUTF16(ref, _hash);
   453   }
   454 }
   456 void
   457 Link::ResetLinkState(bool aNotify, bool aHasHref)
   458 {
   459   nsLinkState defaultState;
   461   // The default state for links with an href is unvisited.
   462   if (aHasHref) {
   463     defaultState = eLinkState_Unvisited;
   464   } else {
   465     defaultState = eLinkState_NotLink;
   466   }
   468   // If !mNeedsRegstration, then either we've never registered, or we're
   469   // currently registered; in either case, we should remove ourself
   470   // from the doc and the history.
   471   if (!mNeedsRegistration && mLinkState != eLinkState_NotLink) {
   472     nsIDocument *doc = mElement->GetCurrentDoc();
   473     if (doc && (mRegistered || mLinkState == eLinkState_Visited)) {
   474       // Tell the document to forget about this link if we've registered
   475       // with it before.
   476       doc->ForgetLink(this);
   477     }
   479     UnregisterFromHistory();
   480   }
   482   // If we have an href, we should register with the history.
   483   mNeedsRegistration = aHasHref;
   485   // If we've cached the URI, reset always invalidates it.
   486   mCachedURI = nullptr;
   487   UpdateURLSearchParams();
   489   // Update our state back to the default.
   490   mLinkState = defaultState;
   492   // We have to be very careful here: if aNotify is false we do NOT
   493   // want to call UpdateState, because that will call into LinkState()
   494   // and try to start off loads, etc.  But ResetLinkState is called
   495   // with aNotify false when things are in inconsistent states, so
   496   // we'll get confused in that situation.  Instead, just silently
   497   // update the link state on mElement. Since we might have set the
   498   // link state to unvisited, make sure to update with that state if
   499   // required.
   500   if (aNotify) {
   501     mElement->UpdateState(aNotify);
   502   } else {
   503     if (mLinkState == eLinkState_Unvisited) {
   504       mElement->UpdateLinkState(NS_EVENT_STATE_UNVISITED);
   505     } else {
   506       mElement->UpdateLinkState(EventStates());
   507     }
   508   }
   509 }
   511 void
   512 Link::UnregisterFromHistory()
   513 {
   514   // If we are not registered, we have nothing to do.
   515   if (!mRegistered) {
   516     return;
   517   }
   519   NS_ASSERTION(mCachedURI, "mRegistered is true, but we have no cached URI?!");
   521   // And tell History to stop tracking us.
   522   if (mHistory) {
   523     nsresult rv = mHistory->UnregisterVisitedCallback(mCachedURI, this);
   524     NS_ASSERTION(NS_SUCCEEDED(rv), "This should only fail if we misuse the API!");
   525     if (NS_SUCCEEDED(rv)) {
   526       mRegistered = false;
   527     }
   528   }
   529 }
   531 already_AddRefed<nsIURI>
   532 Link::GetURIToMutate()
   533 {
   534   nsCOMPtr<nsIURI> uri(GetURI());
   535   if (!uri) {
   536     return nullptr;
   537   }
   538   nsCOMPtr<nsIURI> clone;
   539   (void)uri->Clone(getter_AddRefs(clone));
   540   return clone.forget();
   541 }
   543 void
   544 Link::SetHrefAttribute(nsIURI *aURI)
   545 {
   546   NS_ASSERTION(aURI, "Null URI is illegal!");
   548   nsAutoCString href;
   549   (void)aURI->GetSpec(href);
   550   (void)mElement->SetAttr(kNameSpaceID_None, nsGkAtoms::href,
   551                           NS_ConvertUTF8toUTF16(href), true);
   552 }
   554 size_t
   555 Link::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
   556 {
   557   size_t n = 0;
   559   if (mCachedURI) {
   560     nsCOMPtr<nsISizeOf> iface = do_QueryInterface(mCachedURI);
   561     if (iface) {
   562       n += iface->SizeOfIncludingThis(aMallocSizeOf);
   563     }
   564   }
   566   // The following members don't need to be measured:
   567   // - mElement, because it is a pointer-to-self used to avoid QIs
   568   // - mHistory, because it is non-owning
   570   return n;
   571 }
   573 URLSearchParams*
   574 Link::SearchParams()
   575 {
   576   CreateSearchParamsIfNeeded();
   577   return mSearchParams;
   578 }
   580 void
   581 Link::SetSearchParams(URLSearchParams& aSearchParams)
   582 {
   583   if (mSearchParams) {
   584     mSearchParams->RemoveObserver(this);
   585   }
   587   mSearchParams = &aSearchParams;
   588   mSearchParams->AddObserver(this);
   590   nsAutoString search;
   591   mSearchParams->Serialize(search);
   592   SetSearchInternal(search);
   593 }
   595 void
   596 Link::URLSearchParamsUpdated()
   597 {
   598   MOZ_ASSERT(mSearchParams);
   600   nsString search;
   601   mSearchParams->Serialize(search);
   602   SetSearchInternal(search);
   603 }
   605 void
   606 Link::UpdateURLSearchParams()
   607 {
   608   if (!mSearchParams) {
   609     return;
   610   }
   612   nsAutoCString search;
   613   nsCOMPtr<nsIURI> uri(GetURI());
   614   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
   615   if (url) {
   616     nsresult rv = url->GetQuery(search);
   617     if (NS_FAILED(rv)) {
   618       NS_WARNING("Failed to get the query from a nsIURL.");
   619     }
   620   }
   622   mSearchParams->ParseInput(search, this);
   623 }
   625 void
   626 Link::CreateSearchParamsIfNeeded()
   627 {
   628   if (!mSearchParams) {
   629     mSearchParams = new URLSearchParams();
   630     mSearchParams->AddObserver(this);
   631     UpdateURLSearchParams();
   632   }
   633 }
   635 void
   636 Link::Unlink()
   637 {
   638   if (mSearchParams) {
   639     mSearchParams->RemoveObserver(this);
   640     mSearchParams = nullptr;
   641   }
   642 }
   644 void
   645 Link::Traverse(nsCycleCollectionTraversalCallback &cb)
   646 {
   647   Link* tmp = this;
   648   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams);
   649 }
   651 } // namespace dom
   652 } // namespace mozilla

mercurial