LCOV - app.info - content/base/src/Link.cpp

LCOV - code coverage report
| Current view: | directory - content/base/src - Link.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 239 | 0 | 0.0 %
| Date: | 2012-06-02 | Functions: | 26 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
           2                 :  * vim: sw=2 ts=2 et :
           3                 :  * ***** BEGIN LICENSE BLOCK *****
           4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           5                 :  *
           6                 :  * The contents of this file are subject to the Mozilla Public License Version
           7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           8                 :  * the License. You may obtain a copy of the License at
           9                 :  * http://www.mozilla.org/MPL/
          10                 :  *
          11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          13                 :  * for the specific language governing rights and limitations under the
          14                 :  * License.
          15                 :  *
          16                 :  * The Original Code is mozilla.org code.
          17                 :  *
          18                 :  * The Initial Developer of the Original Code is
          19                 :  * Mozilla Foundation.
          20                 :  * Portions created by the Initial Developer are Copyright (C) 2009
          21                 :  * the Initial Developer. All Rights Reserved.
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   Shawn Wilsher <me@shawnwilsher.com> (Original Author)
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include "Link.h"
          41                 :
          42                 : #include "nsEventStates.h"
          43                 : #include "nsIURL.h"
          44                 : #include "nsISizeOf.h"
          45                 :
          46                 : #include "nsContentUtils.h"
          47                 : #include "nsEscape.h"
          48                 : #include "nsGkAtoms.h"
          49                 : #include "nsString.h"
          50                 : #include "mozAutoDocUpdate.h"
          51                 :
          52                 : #include "mozilla/Services.h"
          53                 :
          54                 : namespace mozilla {
          55                 : namespace dom {
          56                 :
          57               0 : Link::Link(Element *aElement)
          58                 :   : mLinkState(defaultState)
          59                 :   , mRegistered(false)
          60                 :   , mElement(aElement)
          61               0 :   , mHistory(services::GetHistoryService())
          62                 : {
          63               0 :   NS_ABORT_IF_FALSE(mElement, "Must have an element");
          64               0 : }
          65                 :
          66               0 : Link::~Link()
          67                 : {
          68               0 :   UnregisterFromHistory();
          69               0 : }
          70                 :
          71                 : nsLinkState
          72               0 : Link::GetLinkState() const
          73                 : {
          74               0 :   NS_ASSERTION(mRegistered,
          75                 :                "Getting the link state of an unregistered Link!");
          76               0 :   NS_ASSERTION(mLinkState != eLinkState_Unknown,
          77                 :                "Getting the link state with an unknown value!");
          78               0 :   return mLinkState;
          79                 : }
          80                 :
          81                 : void
          82               0 : Link::SetLinkState(nsLinkState aState)
          83                 : {
          84               0 :   NS_ASSERTION(mRegistered,
          85                 :                "Setting the link state of an unregistered Link!");
          86               0 :   NS_ASSERTION(mLinkState != aState,
          87                 :                "Setting state to the currently set state!");
          88                 :
          89                 :   // Set our current state as appropriate.
          90               0 :   mLinkState = aState;
          91                 :
          92                 :   // Per IHistory interface documentation, we are no longer registered.
          93               0 :   mRegistered = false;
          94                 :
          95               0 :   NS_ABORT_IF_FALSE(LinkState() == NS_EVENT_STATE_VISITED ||
          96                 :                     LinkState() == NS_EVENT_STATE_UNVISITED,
          97                 :                     "Unexpected state obtained from LinkState()!");
          98                 :
          99                 :   // Tell the element to update its visited state
         100               0 :   mElement->UpdateState(true);
         101               0 : }
         102                 :
         103                 : nsEventStates
         104               0 : Link::LinkState() const
         105                 : {
         106                 :   // We are a constant method, but we are just lazily doing things and have to
         107                 :   // track that state.  Cast away that constness!
         108               0 :   Link *self = const_cast<Link *>(this);
         109                 :
         110                 :   // If we are not in the document, default to not visited.
         111               0 :   Element *element = self->mElement;
         112               0 :   if (!element->IsInDoc()) {
         113               0 :     self->mLinkState = eLinkState_Unvisited;
         114                 :   }
         115                 :
         116                 :   // If we have not yet registered for notifications and are in an unknown
         117                 :   // state, register now!
         118               0 :   if (!mRegistered && mLinkState == eLinkState_Unknown) {
         119                 :     // First, make sure the href attribute has a valid link (bug 23209).
         120               0 :     nsCOMPtr<nsIURI> hrefURI(GetURI());
         121               0 :     if (!hrefURI) {
         122               0 :       self->mLinkState = eLinkState_NotLink;
         123               0 :       return nsEventStates();
         124                 :     }
         125                 :
         126                 :     // We have a good href, so register with History.
         127               0 :     nsresult rv = mHistory->RegisterVisitedCallback(hrefURI, self);
         128               0 :     if (NS_SUCCEEDED(rv)) {
         129               0 :       self->mRegistered = true;
         130                 :
         131                 :       // Assume that we are not visited until we are told otherwise.
         132               0 :       self->mLinkState = eLinkState_Unvisited;
         133                 :
         134                 :       // And make sure we are in the document's link map.
         135               0 :       nsIDocument *doc = element->GetCurrentDoc();
         136               0 :       if (doc) {
         137               0 :         doc->AddStyleRelevantLink(self);
         138                 :       }
         139                 :     }
         140                 :   }
         141                 :
         142                 :   // Otherwise, return our known state.
         143               0 :   if (mLinkState == eLinkState_Visited) {
         144               0 :     return NS_EVENT_STATE_VISITED;
         145                 :   }
         146                 :
         147               0 :   if (mLinkState == eLinkState_Unvisited) {
         148               0 :     return NS_EVENT_STATE_UNVISITED;
         149                 :   }
         150                 :
         151               0 :   return nsEventStates();
         152                 : }
         153                 :
         154                 : already_AddRefed<nsIURI>
         155               0 : Link::GetURI() const
         156                 : {
         157               0 :   nsCOMPtr<nsIURI> uri(mCachedURI);
         158                 :
         159                 :   // If we have this URI cached, use it.
         160               0 :   if (uri) {
         161               0 :     return uri.forget();
         162                 :   }
         163                 :
         164                 :   // Otherwise obtain it.
         165               0 :   Link *self = const_cast<Link *>(this);
         166               0 :   Element *element = self->mElement;
         167               0 :   uri = element->GetHrefURI();
         168                 :
         169                 :   // We want to cache the URI if the node is in the document.
         170               0 :   if (uri && element->IsInDoc()) {
         171               0 :     mCachedURI = uri;
         172                 :   }
         173                 :
         174               0 :   return uri.forget();
         175                 : }
         176                 :
         177                 : nsresult
         178               0 : Link::SetProtocol(const nsAString &aProtocol)
         179                 : {
         180               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         181               0 :   if (!uri) {
         182                 :     // Ignore failures to be compatible with NS4.
         183               0 :     return NS_OK;
         184                 :   }
         185                 :
         186               0 :   nsAString::const_iterator start, end;
         187               0 :   aProtocol.BeginReading(start);
         188               0 :   aProtocol.EndReading(end);
         189               0 :   nsAString::const_iterator iter(start);
         190               0 :   (void)FindCharInReadable(':', iter, end);
         191               0 :   (void)uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
         192                 :
         193               0 :   SetHrefAttribute(uri);
         194               0 :   return NS_OK;
         195                 : }
         196                 :
         197                 : nsresult
         198               0 : Link::SetHost(const nsAString &aHost)
         199                 : {
         200               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         201               0 :   if (!uri) {
         202                 :     // Ignore failures to be compatible with NS4.
         203               0 :     return NS_OK;
         204                 :   }
         205                 :
         206                 :   // We cannot simply call nsIURI::SetHost because that would treat the name as
         207                 :   // an IPv6 address (like http:://[server:443]/).  We also cannot call
         208                 :   // nsIURI::SetHostPort because that isn't implemented.  Sadfaces.
         209                 :
         210                 :   // First set the hostname.
         211               0 :   nsAString::const_iterator start, end;
         212               0 :   aHost.BeginReading(start);
         213               0 :   aHost.EndReading(end);
         214               0 :   nsAString::const_iterator iter(start);
         215               0 :   (void)FindCharInReadable(':', iter, end);
         216               0 :   NS_ConvertUTF16toUTF8 host(Substring(start, iter));
         217               0 :   (void)uri->SetHost(host);
         218                 :
         219                 :   // Also set the port if needed.
         220               0 :   if (iter != end) {
         221               0 :     iter++;
         222               0 :     if (iter != end) {
         223               0 :       nsAutoString portStr(Substring(iter, end));
         224                 :       nsresult rv;
         225               0 :       PRInt32 port = portStr.ToInteger((PRInt32 *)&rv);
         226               0 :       if (NS_SUCCEEDED(rv)) {
         227               0 :         (void)uri->SetPort(port);
         228                 :       }
         229                 :     }
         230                 :   };
         231                 :
         232               0 :   SetHrefAttribute(uri);
         233               0 :   return NS_OK;
         234                 : }
         235                 :
         236                 : nsresult
         237               0 : Link::SetHostname(const nsAString &aHostname)
         238                 : {
         239               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         240               0 :   if (!uri) {
         241                 :     // Ignore failures to be compatible with NS4.
         242               0 :     return NS_OK;
         243                 :   }
         244                 :
         245               0 :   (void)uri->SetHost(NS_ConvertUTF16toUTF8(aHostname));
         246               0 :   SetHrefAttribute(uri);
         247               0 :   return NS_OK;
         248                 : }
         249                 :
         250                 : nsresult
         251               0 : Link::SetPathname(const nsAString &aPathname)
         252                 : {
         253               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         254               0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
         255               0 :   if (!url) {
         256                 :     // Ignore failures to be compatible with NS4.
         257               0 :     return NS_OK;
         258                 :   }
         259                 :
         260               0 :   (void)url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
         261               0 :   SetHrefAttribute(uri);
         262               0 :   return NS_OK;
         263                 : }
         264                 :
         265                 : nsresult
         266               0 : Link::SetSearch(const nsAString &aSearch)
         267                 : {
         268               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         269               0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
         270               0 :   if (!url) {
         271                 :     // Ignore failures to be compatible with NS4.
         272               0 :     return NS_OK;
         273                 :   }
         274                 :
         275               0 :   (void)url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
         276               0 :   SetHrefAttribute(uri);
         277               0 :   return NS_OK;
         278                 : }
         279                 :
         280                 : nsresult
         281               0 : Link::SetPort(const nsAString &aPort)
         282                 : {
         283               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         284               0 :   if (!uri) {
         285                 :     // Ignore failures to be compatible with NS4.
         286               0 :     return NS_OK;
         287                 :   }
         288                 :
         289                 :   nsresult rv;
         290               0 :   nsAutoString portStr(aPort);
         291               0 :   PRInt32 port = portStr.ToInteger((PRInt32 *)&rv);
         292               0 :   if (NS_FAILED(rv)) {
         293               0 :     return NS_OK;
         294                 :   }
         295                 :
         296               0 :   (void)uri->SetPort(port);
         297               0 :   SetHrefAttribute(uri);
         298               0 :   return NS_OK;
         299                 : }
         300                 :
         301                 : nsresult
         302               0 : Link::SetHash(const nsAString &aHash)
         303                 : {
         304               0 :   nsCOMPtr<nsIURI> uri(GetURIToMutate());
         305               0 :   if (!uri) {
         306                 :     // Ignore failures to be compatible with NS4.
         307               0 :     return NS_OK;
         308                 :   }
         309                 :
         310               0 :   (void)uri->SetRef(NS_ConvertUTF16toUTF8(aHash));
         311               0 :   SetHrefAttribute(uri);
         312               0 :   return NS_OK;
         313                 : }
         314                 :
         315                 : nsresult
         316               0 : Link::GetProtocol(nsAString &_protocol)
         317                 : {
         318               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         319               0 :   if (!uri) {
         320               0 :     _protocol.AssignLiteral("http");
         321                 :   }
         322                 :   else {
         323               0 :     nsCAutoString scheme;
         324               0 :     (void)uri->GetScheme(scheme);
         325               0 :     CopyASCIItoUTF16(scheme, _protocol);
         326                 :   }
         327               0 :   _protocol.Append(PRUnichar(':'));
         328               0 :   return NS_OK;
         329                 : }
         330                 :
         331                 : nsresult
         332               0 : Link::GetHost(nsAString &_host)
         333                 : {
         334               0 :   _host.Truncate();
         335                 :
         336               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         337               0 :   if (!uri) {
         338                 :     // Do not throw!  Not having a valid URI should result in an empty string.
         339               0 :     return NS_OK;
         340                 :   }
         341                 :
         342               0 :   nsCAutoString hostport;
         343               0 :   nsresult rv = uri->GetHostPort(hostport);
         344               0 :   if (NS_SUCCEEDED(rv)) {
         345               0 :     CopyUTF8toUTF16(hostport, _host);
         346                 :   }
         347               0 :   return NS_OK;
         348                 : }
         349                 :
         350                 : nsresult
         351               0 : Link::GetHostname(nsAString &_hostname)
         352                 : {
         353               0 :   _hostname.Truncate();
         354                 :
         355               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         356               0 :   if (!uri) {
         357                 :     // Do not throw!  Not having a valid URI should result in an empty string.
         358               0 :     return NS_OK;
         359                 :   }
         360                 :
         361               0 :   nsCAutoString host;
         362               0 :   nsresult rv = uri->GetHost(host);
         363                 :   // Note that failure to get the host from the URI is not necessarily a bad
         364                 :   // thing.  Some URIs do not have a host.
         365               0 :   if (NS_SUCCEEDED(rv)) {
         366               0 :     CopyUTF8toUTF16(host, _hostname);
         367                 :   }
         368               0 :   return NS_OK;
         369                 : }
         370                 :
         371                 : nsresult
         372               0 : Link::GetPathname(nsAString &_pathname)
         373                 : {
         374               0 :   _pathname.Truncate();
         375                 :
         376               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         377               0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
         378               0 :   if (!url) {
         379                 :     // Do not throw!  Not having a valid URI or URL should result in an empty
         380                 :     // string.
         381               0 :     return NS_OK;
         382                 :   }
         383                 :
         384               0 :   nsCAutoString file;
         385               0 :   nsresult rv = url->GetFilePath(file);
         386               0 :   NS_ENSURE_SUCCESS(rv, rv);
         387               0 :   CopyUTF8toUTF16(file, _pathname);
         388               0 :   return NS_OK;
         389                 : }
         390                 :
         391                 : nsresult
         392               0 : Link::GetSearch(nsAString &_search)
         393                 : {
         394               0 :   _search.Truncate();
         395                 :
         396               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         397               0 :   nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
         398               0 :   if (!url) {
         399                 :     // Do not throw!  Not having a valid URI or URL should result in an empty
         400                 :     // string.
         401               0 :     return NS_OK;
         402                 :   }
         403                 :
         404               0 :   nsCAutoString search;
         405               0 :   nsresult rv = url->GetQuery(search);
         406               0 :   if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
         407               0 :     CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, _search);
         408                 :   }
         409               0 :   return NS_OK;
         410                 : }
         411                 :
         412                 : nsresult
         413               0 : Link::GetPort(nsAString &_port)
         414                 : {
         415               0 :   _port.Truncate();
         416                 :
         417               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         418               0 :   if (!uri) {
         419                 :     // Do not throw!  Not having a valid URI should result in an empty string.
         420               0 :     return NS_OK;
         421                 :   }
         422                 :
         423                 :   PRInt32 port;
         424               0 :   nsresult rv = uri->GetPort(&port);
         425                 :   // Note that failure to get the port from the URI is not necessarily a bad
         426                 :   // thing.  Some URIs do not have a port.
         427               0 :   if (NS_SUCCEEDED(rv) && port != -1) {
         428               0 :     nsAutoString portStr;
         429               0 :     portStr.AppendInt(port, 10);
         430               0 :     _port.Assign(portStr);
         431                 :   }
         432               0 :   return NS_OK;
         433                 : }
         434                 :
         435                 : nsresult
         436               0 : Link::GetHash(nsAString &_hash)
         437                 : {
         438               0 :   _hash.Truncate();
         439                 :
         440               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         441               0 :   if (!uri) {
         442                 :     // Do not throw!  Not having a valid URI should result in an empty
         443                 :     // string.
         444               0 :     return NS_OK;
         445                 :   }
         446                 :
         447               0 :   nsCAutoString ref;
         448               0 :   nsresult rv = uri->GetRef(ref);
         449               0 :   if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
         450               0 :     NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
         451               0 :     _hash.Assign(PRUnichar('#'));
         452               0 :     AppendUTF8toUTF16(ref, _hash);
         453                 :   }
         454               0 :   return NS_OK;
         455                 : }
         456                 :
         457                 : void
         458               0 : Link::ResetLinkState(bool aNotify)
         459                 : {
         460                 :   // If we are in our default state, bail early.
         461               0 :   if (mLinkState == defaultState) {
         462               0 :     return;
         463                 :   }
         464                 :
         465               0 :   Element *element = mElement;
         466                 :
         467                 :   // Tell the document to forget about this link if we were a link before.
         468               0 :   nsIDocument *doc = element->GetCurrentDoc();
         469               0 :   if (doc && mLinkState != eLinkState_NotLink) {
         470               0 :     doc->ForgetLink(this);
         471                 :   }
         472                 :
         473               0 :   UnregisterFromHistory();
         474                 :
         475                 :   // Update our state back to the default.
         476               0 :   mLinkState = defaultState;
         477                 :
         478                 :   // Get rid of our cached URI.
         479               0 :   mCachedURI = nsnull;
         480                 :
         481                 :   // We have to be very careful here: if aNotify is false we do NOT
         482                 :   // want to call UpdateState, because that will call into LinkState()
         483                 :   // and try to start off loads, etc.  But ResetLinkState is called
         484                 :   // with aNotify false when things are in inconsistent states, so
         485                 :   // we'll get confused in that situation.  Instead, just silently
         486                 :   // update the link state on mElement.
         487               0 :   if (aNotify) {
         488               0 :     mElement->UpdateState(aNotify);
         489                 :   } else {
         490               0 :     mElement->UpdateLinkState(nsEventStates());
         491                 :   }
         492                 : }
         493                 :
         494                 : void
         495               0 : Link::UnregisterFromHistory()
         496                 : {
         497                 :   // If we are not registered, we have nothing to do.
         498               0 :   if (!mRegistered) {
         499               0 :     return;
         500                 :   }
         501                 :
         502               0 :   NS_ASSERTION(mCachedURI, "mRegistered is true, but we have no cached URI?!");
         503                 :
         504                 :   // And tell History to stop tracking us.
         505               0 :   nsresult rv = mHistory->UnregisterVisitedCallback(mCachedURI, this);
         506               0 :   NS_ASSERTION(NS_SUCCEEDED(rv), "This should only fail if we misuse the API!");
         507               0 :   if (NS_SUCCEEDED(rv)) {
         508               0 :     mRegistered = false;
         509                 :   }
         510                 : }
         511                 :
         512                 : already_AddRefed<nsIURI>
         513               0 : Link::GetURIToMutate()
         514                 : {
         515               0 :   nsCOMPtr<nsIURI> uri(GetURI());
         516               0 :   if (!uri) {
         517               0 :     return nsnull;
         518                 :   }
         519               0 :   nsCOMPtr<nsIURI> clone;
         520               0 :   (void)uri->Clone(getter_AddRefs(clone));
         521               0 :   return clone.forget();
         522                 : }
         523                 :
         524                 : void
         525               0 : Link::SetHrefAttribute(nsIURI *aURI)
         526                 : {
         527               0 :   NS_ASSERTION(aURI, "Null URI is illegal!");
         528                 :
         529               0 :   nsCAutoString href;
         530               0 :   (void)aURI->GetSpec(href);
         531                 :   (void)mElement->SetAttr(kNameSpaceID_None, nsGkAtoms::href,
         532               0 :                           NS_ConvertUTF8toUTF16(href), true);
         533               0 : }
         534                 :
         535                 : size_t
         536               0 : Link::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
         537                 : {
         538               0 :   size_t n = 0;
         539                 :
         540               0 :   if (mCachedURI) {
         541               0 :     nsCOMPtr<nsISizeOf> iface = do_QueryInterface(mCachedURI);
         542               0 :     if (iface) {
         543               0 :       n += iface->SizeOfIncludingThis(aMallocSizeOf);
         544                 :     }
         545                 :   }
         546                 :
         547                 :   // The following members don't need to be measured:
         548                 :   // - mElement, because it is a pointer-to-self used to avoid QIs
         549                 :   // - mHistory, because it is non-owning
         550                 :
         551               0 :   return n;
         552                 : }
         553                 :
         554                 : } // namespace dom
         555                 : } // namespace mozilla

Generated by: LCOV version 1.7