1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/Link.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,652 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=2 et : 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "Link.h" 1.11 + 1.12 +#include "mozilla/EventStates.h" 1.13 +#include "mozilla/MemoryReporting.h" 1.14 +#include "mozilla/dom/Element.h" 1.15 +#include "nsIURL.h" 1.16 +#include "nsISizeOf.h" 1.17 + 1.18 +#include "nsEscape.h" 1.19 +#include "nsGkAtoms.h" 1.20 +#include "nsString.h" 1.21 +#include "mozAutoDocUpdate.h" 1.22 + 1.23 +#include "mozilla/Services.h" 1.24 + 1.25 +namespace mozilla { 1.26 +namespace dom { 1.27 + 1.28 +Link::Link(Element *aElement) 1.29 + : mElement(aElement) 1.30 + , mHistory(services::GetHistoryService()) 1.31 + , mLinkState(eLinkState_NotLink) 1.32 + , mNeedsRegistration(false) 1.33 + , mRegistered(false) 1.34 +{ 1.35 + NS_ABORT_IF_FALSE(mElement, "Must have an element"); 1.36 +} 1.37 + 1.38 +Link::~Link() 1.39 +{ 1.40 + UnregisterFromHistory(); 1.41 +} 1.42 + 1.43 +bool 1.44 +Link::ElementHasHref() const 1.45 +{ 1.46 + return ((!mElement->IsSVG() && mElement->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) 1.47 + || (!mElement->IsHTML() && mElement->HasAttr(kNameSpaceID_XLink, nsGkAtoms::href))); 1.48 +} 1.49 + 1.50 +void 1.51 +Link::SetLinkState(nsLinkState aState) 1.52 +{ 1.53 + NS_ASSERTION(mRegistered, 1.54 + "Setting the link state of an unregistered Link!"); 1.55 + NS_ASSERTION(mLinkState != aState, 1.56 + "Setting state to the currently set state!"); 1.57 + 1.58 + // Set our current state as appropriate. 1.59 + mLinkState = aState; 1.60 + 1.61 + // Per IHistory interface documentation, we are no longer registered. 1.62 + mRegistered = false; 1.63 + 1.64 + NS_ABORT_IF_FALSE(LinkState() == NS_EVENT_STATE_VISITED || 1.65 + LinkState() == NS_EVENT_STATE_UNVISITED, 1.66 + "Unexpected state obtained from LinkState()!"); 1.67 + 1.68 + // Tell the element to update its visited state 1.69 + mElement->UpdateState(true); 1.70 +} 1.71 + 1.72 +EventStates 1.73 +Link::LinkState() const 1.74 +{ 1.75 + // We are a constant method, but we are just lazily doing things and have to 1.76 + // track that state. Cast away that constness! 1.77 + Link *self = const_cast<Link *>(this); 1.78 + 1.79 + Element *element = self->mElement; 1.80 + 1.81 + // If we have not yet registered for notifications and need to, 1.82 + // due to our href changing, register now! 1.83 + if (!mRegistered && mNeedsRegistration && element->IsInDoc()) { 1.84 + // Only try and register once. 1.85 + self->mNeedsRegistration = false; 1.86 + 1.87 + nsCOMPtr<nsIURI> hrefURI(GetURI()); 1.88 + 1.89 + // Assume that we are not visited until we are told otherwise. 1.90 + self->mLinkState = eLinkState_Unvisited; 1.91 + 1.92 + // Make sure the href attribute has a valid link (bug 23209). 1.93 + // If we have a good href, register with History if available. 1.94 + if (mHistory && hrefURI) { 1.95 + nsresult rv = mHistory->RegisterVisitedCallback(hrefURI, self); 1.96 + if (NS_SUCCEEDED(rv)) { 1.97 + self->mRegistered = true; 1.98 + 1.99 + // And make sure we are in the document's link map. 1.100 + element->GetCurrentDoc()->AddStyleRelevantLink(self); 1.101 + } 1.102 + } 1.103 + } 1.104 + 1.105 + // Otherwise, return our known state. 1.106 + if (mLinkState == eLinkState_Visited) { 1.107 + return NS_EVENT_STATE_VISITED; 1.108 + } 1.109 + 1.110 + if (mLinkState == eLinkState_Unvisited) { 1.111 + return NS_EVENT_STATE_UNVISITED; 1.112 + } 1.113 + 1.114 + return EventStates(); 1.115 +} 1.116 + 1.117 +nsIURI* 1.118 +Link::GetURI() const 1.119 +{ 1.120 + // If we have this URI cached, use it. 1.121 + if (mCachedURI) { 1.122 + return mCachedURI; 1.123 + } 1.124 + 1.125 + // Otherwise obtain it. 1.126 + Link *self = const_cast<Link *>(this); 1.127 + Element *element = self->mElement; 1.128 + mCachedURI = element->GetHrefURI(); 1.129 + 1.130 + return mCachedURI; 1.131 +} 1.132 + 1.133 +void 1.134 +Link::SetProtocol(const nsAString &aProtocol) 1.135 +{ 1.136 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.137 + if (!uri) { 1.138 + // Ignore failures to be compatible with NS4. 1.139 + return; 1.140 + } 1.141 + 1.142 + nsAString::const_iterator start, end; 1.143 + aProtocol.BeginReading(start); 1.144 + aProtocol.EndReading(end); 1.145 + nsAString::const_iterator iter(start); 1.146 + (void)FindCharInReadable(':', iter, end); 1.147 + (void)uri->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))); 1.148 + 1.149 + SetHrefAttribute(uri); 1.150 +} 1.151 + 1.152 +void 1.153 +Link::SetPassword(const nsAString &aPassword) 1.154 +{ 1.155 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.156 + if (!uri) { 1.157 + // Ignore failures to be compatible with NS4. 1.158 + return; 1.159 + } 1.160 + 1.161 + uri->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); 1.162 + SetHrefAttribute(uri); 1.163 +} 1.164 + 1.165 +void 1.166 +Link::SetUsername(const nsAString &aUsername) 1.167 +{ 1.168 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.169 + if (!uri) { 1.170 + // Ignore failures to be compatible with NS4. 1.171 + return; 1.172 + } 1.173 + 1.174 + uri->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); 1.175 + SetHrefAttribute(uri); 1.176 +} 1.177 + 1.178 +void 1.179 +Link::SetHost(const nsAString &aHost) 1.180 +{ 1.181 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.182 + if (!uri) { 1.183 + // Ignore failures to be compatible with NS4. 1.184 + return; 1.185 + } 1.186 + 1.187 + (void)uri->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); 1.188 + SetHrefAttribute(uri); 1.189 +} 1.190 + 1.191 +void 1.192 +Link::SetHostname(const nsAString &aHostname) 1.193 +{ 1.194 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.195 + if (!uri) { 1.196 + // Ignore failures to be compatible with NS4. 1.197 + return; 1.198 + } 1.199 + 1.200 + (void)uri->SetHost(NS_ConvertUTF16toUTF8(aHostname)); 1.201 + SetHrefAttribute(uri); 1.202 +} 1.203 + 1.204 +void 1.205 +Link::SetPathname(const nsAString &aPathname) 1.206 +{ 1.207 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.208 + nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); 1.209 + if (!url) { 1.210 + // Ignore failures to be compatible with NS4. 1.211 + return; 1.212 + } 1.213 + 1.214 + (void)url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); 1.215 + SetHrefAttribute(uri); 1.216 +} 1.217 + 1.218 +void 1.219 +Link::SetSearch(const nsAString& aSearch) 1.220 +{ 1.221 + SetSearchInternal(aSearch); 1.222 + UpdateURLSearchParams(); 1.223 +} 1.224 + 1.225 +void 1.226 +Link::SetSearchInternal(const nsAString& aSearch) 1.227 +{ 1.228 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.229 + nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); 1.230 + if (!url) { 1.231 + // Ignore failures to be compatible with NS4. 1.232 + return; 1.233 + } 1.234 + 1.235 + (void)url->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); 1.236 + SetHrefAttribute(uri); 1.237 +} 1.238 + 1.239 +void 1.240 +Link::SetPort(const nsAString &aPort) 1.241 +{ 1.242 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.243 + if (!uri) { 1.244 + // Ignore failures to be compatible with NS4. 1.245 + return; 1.246 + } 1.247 + 1.248 + nsresult rv; 1.249 + nsAutoString portStr(aPort); 1.250 + 1.251 + // nsIURI uses -1 as default value. 1.252 + int32_t port = -1; 1.253 + if (!aPort.IsEmpty()) { 1.254 + port = portStr.ToInteger(&rv); 1.255 + if (NS_FAILED(rv)) { 1.256 + return; 1.257 + } 1.258 + } 1.259 + 1.260 + (void)uri->SetPort(port); 1.261 + SetHrefAttribute(uri); 1.262 +} 1.263 + 1.264 +void 1.265 +Link::SetHash(const nsAString &aHash) 1.266 +{ 1.267 + nsCOMPtr<nsIURI> uri(GetURIToMutate()); 1.268 + if (!uri) { 1.269 + // Ignore failures to be compatible with NS4. 1.270 + return; 1.271 + } 1.272 + 1.273 + (void)uri->SetRef(NS_ConvertUTF16toUTF8(aHash)); 1.274 + SetHrefAttribute(uri); 1.275 +} 1.276 + 1.277 +void 1.278 +Link::GetOrigin(nsAString &aOrigin) 1.279 +{ 1.280 + aOrigin.Truncate(); 1.281 + 1.282 + nsCOMPtr<nsIURI> uri(GetURI()); 1.283 + if (!uri) { 1.284 + return; 1.285 + } 1.286 + 1.287 + nsString origin; 1.288 + nsContentUtils::GetUTFNonNullOrigin(uri, origin); 1.289 + aOrigin.Assign(origin); 1.290 +} 1.291 + 1.292 +void 1.293 +Link::GetProtocol(nsAString &_protocol) 1.294 +{ 1.295 + nsCOMPtr<nsIURI> uri(GetURI()); 1.296 + if (!uri) { 1.297 + _protocol.AssignLiteral("http"); 1.298 + } 1.299 + else { 1.300 + nsAutoCString scheme; 1.301 + (void)uri->GetScheme(scheme); 1.302 + CopyASCIItoUTF16(scheme, _protocol); 1.303 + } 1.304 + _protocol.Append(char16_t(':')); 1.305 + return; 1.306 +} 1.307 + 1.308 +void 1.309 +Link::GetUsername(nsAString& aUsername) 1.310 +{ 1.311 + aUsername.Truncate(); 1.312 + 1.313 + nsCOMPtr<nsIURI> uri(GetURI()); 1.314 + if (!uri) { 1.315 + return; 1.316 + } 1.317 + 1.318 + nsAutoCString username; 1.319 + uri->GetUsername(username); 1.320 + CopyASCIItoUTF16(username, aUsername); 1.321 +} 1.322 + 1.323 +void 1.324 +Link::GetPassword(nsAString &aPassword) 1.325 +{ 1.326 + aPassword.Truncate(); 1.327 + 1.328 + nsCOMPtr<nsIURI> uri(GetURI()); 1.329 + if (!uri) { 1.330 + return; 1.331 + } 1.332 + 1.333 + nsAutoCString password; 1.334 + uri->GetPassword(password); 1.335 + CopyASCIItoUTF16(password, aPassword); 1.336 +} 1.337 + 1.338 +void 1.339 +Link::GetHost(nsAString &_host) 1.340 +{ 1.341 + _host.Truncate(); 1.342 + 1.343 + nsCOMPtr<nsIURI> uri(GetURI()); 1.344 + if (!uri) { 1.345 + // Do not throw! Not having a valid URI should result in an empty string. 1.346 + return; 1.347 + } 1.348 + 1.349 + nsAutoCString hostport; 1.350 + nsresult rv = uri->GetHostPort(hostport); 1.351 + if (NS_SUCCEEDED(rv)) { 1.352 + CopyUTF8toUTF16(hostport, _host); 1.353 + } 1.354 +} 1.355 + 1.356 +void 1.357 +Link::GetHostname(nsAString &_hostname) 1.358 +{ 1.359 + _hostname.Truncate(); 1.360 + 1.361 + nsCOMPtr<nsIURI> uri(GetURI()); 1.362 + if (!uri) { 1.363 + // Do not throw! Not having a valid URI should result in an empty string. 1.364 + return; 1.365 + } 1.366 + 1.367 + nsAutoCString host; 1.368 + nsresult rv = uri->GetHost(host); 1.369 + // Note that failure to get the host from the URI is not necessarily a bad 1.370 + // thing. Some URIs do not have a host. 1.371 + if (NS_SUCCEEDED(rv)) { 1.372 + CopyUTF8toUTF16(host, _hostname); 1.373 + } 1.374 +} 1.375 + 1.376 +void 1.377 +Link::GetPathname(nsAString &_pathname) 1.378 +{ 1.379 + _pathname.Truncate(); 1.380 + 1.381 + nsCOMPtr<nsIURI> uri(GetURI()); 1.382 + nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); 1.383 + if (!url) { 1.384 + // Do not throw! Not having a valid URI or URL should result in an empty 1.385 + // string. 1.386 + return; 1.387 + } 1.388 + 1.389 + nsAutoCString file; 1.390 + nsresult rv = url->GetFilePath(file); 1.391 + if (NS_SUCCEEDED(rv)) { 1.392 + CopyUTF8toUTF16(file, _pathname); 1.393 + } 1.394 +} 1.395 + 1.396 +void 1.397 +Link::GetSearch(nsAString &_search) 1.398 +{ 1.399 + _search.Truncate(); 1.400 + 1.401 + nsCOMPtr<nsIURI> uri(GetURI()); 1.402 + nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); 1.403 + if (!url) { 1.404 + // Do not throw! Not having a valid URI or URL should result in an empty 1.405 + // string. 1.406 + return; 1.407 + } 1.408 + 1.409 + nsAutoCString search; 1.410 + nsresult rv = url->GetQuery(search); 1.411 + if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { 1.412 + CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, _search); 1.413 + } 1.414 +} 1.415 + 1.416 +void 1.417 +Link::GetPort(nsAString &_port) 1.418 +{ 1.419 + _port.Truncate(); 1.420 + 1.421 + nsCOMPtr<nsIURI> uri(GetURI()); 1.422 + if (!uri) { 1.423 + // Do not throw! Not having a valid URI should result in an empty string. 1.424 + return; 1.425 + } 1.426 + 1.427 + int32_t port; 1.428 + nsresult rv = uri->GetPort(&port); 1.429 + // Note that failure to get the port from the URI is not necessarily a bad 1.430 + // thing. Some URIs do not have a port. 1.431 + if (NS_SUCCEEDED(rv) && port != -1) { 1.432 + nsAutoString portStr; 1.433 + portStr.AppendInt(port, 10); 1.434 + _port.Assign(portStr); 1.435 + } 1.436 +} 1.437 + 1.438 +void 1.439 +Link::GetHash(nsAString &_hash) 1.440 +{ 1.441 + _hash.Truncate(); 1.442 + 1.443 + nsCOMPtr<nsIURI> uri(GetURI()); 1.444 + if (!uri) { 1.445 + // Do not throw! Not having a valid URI should result in an empty 1.446 + // string. 1.447 + return; 1.448 + } 1.449 + 1.450 + nsAutoCString ref; 1.451 + nsresult rv = uri->GetRef(ref); 1.452 + if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { 1.453 + NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes! 1.454 + _hash.Assign(char16_t('#')); 1.455 + AppendUTF8toUTF16(ref, _hash); 1.456 + } 1.457 +} 1.458 + 1.459 +void 1.460 +Link::ResetLinkState(bool aNotify, bool aHasHref) 1.461 +{ 1.462 + nsLinkState defaultState; 1.463 + 1.464 + // The default state for links with an href is unvisited. 1.465 + if (aHasHref) { 1.466 + defaultState = eLinkState_Unvisited; 1.467 + } else { 1.468 + defaultState = eLinkState_NotLink; 1.469 + } 1.470 + 1.471 + // If !mNeedsRegstration, then either we've never registered, or we're 1.472 + // currently registered; in either case, we should remove ourself 1.473 + // from the doc and the history. 1.474 + if (!mNeedsRegistration && mLinkState != eLinkState_NotLink) { 1.475 + nsIDocument *doc = mElement->GetCurrentDoc(); 1.476 + if (doc && (mRegistered || mLinkState == eLinkState_Visited)) { 1.477 + // Tell the document to forget about this link if we've registered 1.478 + // with it before. 1.479 + doc->ForgetLink(this); 1.480 + } 1.481 + 1.482 + UnregisterFromHistory(); 1.483 + } 1.484 + 1.485 + // If we have an href, we should register with the history. 1.486 + mNeedsRegistration = aHasHref; 1.487 + 1.488 + // If we've cached the URI, reset always invalidates it. 1.489 + mCachedURI = nullptr; 1.490 + UpdateURLSearchParams(); 1.491 + 1.492 + // Update our state back to the default. 1.493 + mLinkState = defaultState; 1.494 + 1.495 + // We have to be very careful here: if aNotify is false we do NOT 1.496 + // want to call UpdateState, because that will call into LinkState() 1.497 + // and try to start off loads, etc. But ResetLinkState is called 1.498 + // with aNotify false when things are in inconsistent states, so 1.499 + // we'll get confused in that situation. Instead, just silently 1.500 + // update the link state on mElement. Since we might have set the 1.501 + // link state to unvisited, make sure to update with that state if 1.502 + // required. 1.503 + if (aNotify) { 1.504 + mElement->UpdateState(aNotify); 1.505 + } else { 1.506 + if (mLinkState == eLinkState_Unvisited) { 1.507 + mElement->UpdateLinkState(NS_EVENT_STATE_UNVISITED); 1.508 + } else { 1.509 + mElement->UpdateLinkState(EventStates()); 1.510 + } 1.511 + } 1.512 +} 1.513 + 1.514 +void 1.515 +Link::UnregisterFromHistory() 1.516 +{ 1.517 + // If we are not registered, we have nothing to do. 1.518 + if (!mRegistered) { 1.519 + return; 1.520 + } 1.521 + 1.522 + NS_ASSERTION(mCachedURI, "mRegistered is true, but we have no cached URI?!"); 1.523 + 1.524 + // And tell History to stop tracking us. 1.525 + if (mHistory) { 1.526 + nsresult rv = mHistory->UnregisterVisitedCallback(mCachedURI, this); 1.527 + NS_ASSERTION(NS_SUCCEEDED(rv), "This should only fail if we misuse the API!"); 1.528 + if (NS_SUCCEEDED(rv)) { 1.529 + mRegistered = false; 1.530 + } 1.531 + } 1.532 +} 1.533 + 1.534 +already_AddRefed<nsIURI> 1.535 +Link::GetURIToMutate() 1.536 +{ 1.537 + nsCOMPtr<nsIURI> uri(GetURI()); 1.538 + if (!uri) { 1.539 + return nullptr; 1.540 + } 1.541 + nsCOMPtr<nsIURI> clone; 1.542 + (void)uri->Clone(getter_AddRefs(clone)); 1.543 + return clone.forget(); 1.544 +} 1.545 + 1.546 +void 1.547 +Link::SetHrefAttribute(nsIURI *aURI) 1.548 +{ 1.549 + NS_ASSERTION(aURI, "Null URI is illegal!"); 1.550 + 1.551 + nsAutoCString href; 1.552 + (void)aURI->GetSpec(href); 1.553 + (void)mElement->SetAttr(kNameSpaceID_None, nsGkAtoms::href, 1.554 + NS_ConvertUTF8toUTF16(href), true); 1.555 +} 1.556 + 1.557 +size_t 1.558 +Link::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.559 +{ 1.560 + size_t n = 0; 1.561 + 1.562 + if (mCachedURI) { 1.563 + nsCOMPtr<nsISizeOf> iface = do_QueryInterface(mCachedURI); 1.564 + if (iface) { 1.565 + n += iface->SizeOfIncludingThis(aMallocSizeOf); 1.566 + } 1.567 + } 1.568 + 1.569 + // The following members don't need to be measured: 1.570 + // - mElement, because it is a pointer-to-self used to avoid QIs 1.571 + // - mHistory, because it is non-owning 1.572 + 1.573 + return n; 1.574 +} 1.575 + 1.576 +URLSearchParams* 1.577 +Link::SearchParams() 1.578 +{ 1.579 + CreateSearchParamsIfNeeded(); 1.580 + return mSearchParams; 1.581 +} 1.582 + 1.583 +void 1.584 +Link::SetSearchParams(URLSearchParams& aSearchParams) 1.585 +{ 1.586 + if (mSearchParams) { 1.587 + mSearchParams->RemoveObserver(this); 1.588 + } 1.589 + 1.590 + mSearchParams = &aSearchParams; 1.591 + mSearchParams->AddObserver(this); 1.592 + 1.593 + nsAutoString search; 1.594 + mSearchParams->Serialize(search); 1.595 + SetSearchInternal(search); 1.596 +} 1.597 + 1.598 +void 1.599 +Link::URLSearchParamsUpdated() 1.600 +{ 1.601 + MOZ_ASSERT(mSearchParams); 1.602 + 1.603 + nsString search; 1.604 + mSearchParams->Serialize(search); 1.605 + SetSearchInternal(search); 1.606 +} 1.607 + 1.608 +void 1.609 +Link::UpdateURLSearchParams() 1.610 +{ 1.611 + if (!mSearchParams) { 1.612 + return; 1.613 + } 1.614 + 1.615 + nsAutoCString search; 1.616 + nsCOMPtr<nsIURI> uri(GetURI()); 1.617 + nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); 1.618 + if (url) { 1.619 + nsresult rv = url->GetQuery(search); 1.620 + if (NS_FAILED(rv)) { 1.621 + NS_WARNING("Failed to get the query from a nsIURL."); 1.622 + } 1.623 + } 1.624 + 1.625 + mSearchParams->ParseInput(search, this); 1.626 +} 1.627 + 1.628 +void 1.629 +Link::CreateSearchParamsIfNeeded() 1.630 +{ 1.631 + if (!mSearchParams) { 1.632 + mSearchParams = new URLSearchParams(); 1.633 + mSearchParams->AddObserver(this); 1.634 + UpdateURLSearchParams(); 1.635 + } 1.636 +} 1.637 + 1.638 +void 1.639 +Link::Unlink() 1.640 +{ 1.641 + if (mSearchParams) { 1.642 + mSearchParams->RemoveObserver(this); 1.643 + mSearchParams = nullptr; 1.644 + } 1.645 +} 1.646 + 1.647 +void 1.648 +Link::Traverse(nsCycleCollectionTraversalCallback &cb) 1.649 +{ 1.650 + Link* tmp = this; 1.651 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams); 1.652 +} 1.653 + 1.654 +} // namespace dom 1.655 +} // namespace mozilla