content/base/src/Link.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial