1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla browser.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications, Inc.
19 : * Portions created by the Initial Developer are Copyright (C) 1999
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Radha Kulkarni <radha@netscape.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : // Local Includes
40 : #include "nsSHEntry.h"
41 : #include "nsXPIDLString.h"
42 : #include "nsReadableUtils.h"
43 : #include "nsIDocShellLoadInfo.h"
44 : #include "nsIDocShellTreeItem.h"
45 : #include "nsIDocument.h"
46 : #include "nsIDOMDocument.h"
47 : #include "nsISHistory.h"
48 : #include "nsISHistoryInternal.h"
49 : #include "nsDocShellEditorData.h"
50 : #include "nsSHEntryShared.h"
51 : #include "nsILayoutHistoryState.h"
52 : #include "nsIContentViewer.h"
53 : #include "nsISupportsArray.h"
54 :
55 : namespace dom = mozilla::dom;
56 :
57 : static PRUint32 gEntryID = 0;
58 :
59 : //*****************************************************************************
60 : //*** nsSHEntry: Object Management
61 : //*****************************************************************************
62 :
63 :
64 0 : nsSHEntry::nsSHEntry()
65 : : mLoadType(0)
66 : , mID(gEntryID++)
67 : , mScrollPositionX(0)
68 : , mScrollPositionY(0)
69 : , mParent(nsnull)
70 0 : , mURIWasModified(false)
71 : {
72 0 : mShared = new nsSHEntryShared();
73 0 : }
74 :
75 0 : nsSHEntry::nsSHEntry(const nsSHEntry &other)
76 : : mShared(other.mShared)
77 : , mURI(other.mURI)
78 : , mReferrerURI(other.mReferrerURI)
79 : , mTitle(other.mTitle)
80 : , mPostData(other.mPostData)
81 : , mLoadType(0) // XXX why not copy?
82 : , mID(other.mID)
83 : , mScrollPositionX(0) // XXX why not copy?
84 : , mScrollPositionY(0) // XXX why not copy?
85 : , mParent(other.mParent)
86 : , mURIWasModified(other.mURIWasModified)
87 0 : , mStateData(other.mStateData)
88 : {
89 0 : }
90 :
91 : static bool
92 0 : ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
93 : {
94 0 : if (aEntry) {
95 0 : aEntry->SetParent(nsnull);
96 : }
97 0 : return true;
98 : }
99 :
100 0 : nsSHEntry::~nsSHEntry()
101 : {
102 : // Null out the mParent pointers on all our kids.
103 0 : mChildren.EnumerateForwards(ClearParentPtr, nsnull);
104 0 : }
105 :
106 : //*****************************************************************************
107 : // nsSHEntry: nsISupports
108 : //*****************************************************************************
109 :
110 0 : NS_IMPL_ISUPPORTS4(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry,
111 : nsISHEntryInternal)
112 :
113 : //*****************************************************************************
114 : // nsSHEntry: nsISHEntry
115 : //*****************************************************************************
116 :
117 0 : NS_IMETHODIMP nsSHEntry::SetScrollPosition(PRInt32 x, PRInt32 y)
118 : {
119 0 : mScrollPositionX = x;
120 0 : mScrollPositionY = y;
121 0 : return NS_OK;
122 : }
123 :
124 0 : NS_IMETHODIMP nsSHEntry::GetScrollPosition(PRInt32 *x, PRInt32 *y)
125 : {
126 0 : *x = mScrollPositionX;
127 0 : *y = mScrollPositionY;
128 0 : return NS_OK;
129 : }
130 :
131 0 : NS_IMETHODIMP nsSHEntry::GetURIWasModified(bool* aOut)
132 : {
133 0 : *aOut = mURIWasModified;
134 0 : return NS_OK;
135 : }
136 :
137 0 : NS_IMETHODIMP nsSHEntry::SetURIWasModified(bool aIn)
138 : {
139 0 : mURIWasModified = aIn;
140 0 : return NS_OK;
141 : }
142 :
143 0 : NS_IMETHODIMP nsSHEntry::GetURI(nsIURI** aURI)
144 : {
145 0 : *aURI = mURI;
146 0 : NS_IF_ADDREF(*aURI);
147 0 : return NS_OK;
148 : }
149 :
150 0 : NS_IMETHODIMP nsSHEntry::SetURI(nsIURI* aURI)
151 : {
152 0 : mURI = aURI;
153 0 : return NS_OK;
154 : }
155 :
156 0 : NS_IMETHODIMP nsSHEntry::GetReferrerURI(nsIURI **aReferrerURI)
157 : {
158 0 : *aReferrerURI = mReferrerURI;
159 0 : NS_IF_ADDREF(*aReferrerURI);
160 0 : return NS_OK;
161 : }
162 :
163 0 : NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
164 : {
165 0 : mReferrerURI = aReferrerURI;
166 0 : return NS_OK;
167 : }
168 :
169 : NS_IMETHODIMP
170 0 : nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
171 : {
172 0 : return mShared->SetContentViewer(aViewer);
173 : }
174 :
175 : NS_IMETHODIMP
176 0 : nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
177 : {
178 0 : *aResult = mShared->mContentViewer;
179 0 : NS_IF_ADDREF(*aResult);
180 0 : return NS_OK;
181 : }
182 :
183 : NS_IMETHODIMP
184 0 : nsSHEntry::GetAnyContentViewer(nsISHEntry **aOwnerEntry,
185 : nsIContentViewer **aResult)
186 : {
187 : // Find a content viewer in the root node or any of its children,
188 : // assuming that there is only one content viewer total in any one
189 : // nsSHEntry tree
190 0 : GetContentViewer(aResult);
191 0 : if (*aResult) {
192 : #ifdef DEBUG_PAGE_CACHE
193 : printf("Found content viewer\n");
194 : #endif
195 0 : *aOwnerEntry = this;
196 0 : NS_ADDREF(*aOwnerEntry);
197 0 : return NS_OK;
198 : }
199 : // The root SHEntry doesn't have a ContentViewer, so check child nodes
200 0 : for (PRInt32 i = 0; i < mChildren.Count(); i++) {
201 0 : nsISHEntry* child = mChildren[i];
202 0 : if (child) {
203 : #ifdef DEBUG_PAGE_CACHE
204 : printf("Evaluating SHEntry child %d\n", i);
205 : #endif
206 0 : child->GetAnyContentViewer(aOwnerEntry, aResult);
207 0 : if (*aResult) {
208 0 : return NS_OK;
209 : }
210 : }
211 : }
212 0 : return NS_OK;
213 : }
214 :
215 : NS_IMETHODIMP
216 0 : nsSHEntry::SetSticky(bool aSticky)
217 : {
218 0 : mShared->mSticky = aSticky;
219 0 : return NS_OK;
220 : }
221 :
222 : NS_IMETHODIMP
223 0 : nsSHEntry::GetSticky(bool *aSticky)
224 : {
225 0 : *aSticky = mShared->mSticky;
226 0 : return NS_OK;
227 : }
228 :
229 0 : NS_IMETHODIMP nsSHEntry::GetTitle(PRUnichar** aTitle)
230 : {
231 : // Check for empty title...
232 0 : if (mTitle.IsEmpty() && mURI) {
233 : // Default title is the URL.
234 0 : nsCAutoString spec;
235 0 : if (NS_SUCCEEDED(mURI->GetSpec(spec)))
236 0 : AppendUTF8toUTF16(spec, mTitle);
237 : }
238 :
239 0 : *aTitle = ToNewUnicode(mTitle);
240 0 : return NS_OK;
241 : }
242 :
243 0 : NS_IMETHODIMP nsSHEntry::SetTitle(const nsAString &aTitle)
244 : {
245 0 : mTitle = aTitle;
246 0 : return NS_OK;
247 : }
248 :
249 0 : NS_IMETHODIMP nsSHEntry::GetPostData(nsIInputStream** aResult)
250 : {
251 0 : *aResult = mPostData;
252 0 : NS_IF_ADDREF(*aResult);
253 0 : return NS_OK;
254 : }
255 :
256 0 : NS_IMETHODIMP nsSHEntry::SetPostData(nsIInputStream* aPostData)
257 : {
258 0 : mPostData = aPostData;
259 0 : return NS_OK;
260 : }
261 :
262 0 : NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult)
263 : {
264 0 : *aResult = mShared->mLayoutHistoryState;
265 0 : NS_IF_ADDREF(*aResult);
266 0 : return NS_OK;
267 : }
268 :
269 0 : NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState)
270 : {
271 0 : mShared->mLayoutHistoryState = aState;
272 0 : if (mShared->mLayoutHistoryState) {
273 0 : mShared->mLayoutHistoryState->
274 0 : SetScrollPositionOnly(!mShared->mSaveLayoutState);
275 : }
276 :
277 0 : return NS_OK;
278 : }
279 :
280 0 : NS_IMETHODIMP nsSHEntry::GetLoadType(PRUint32 * aResult)
281 : {
282 0 : *aResult = mLoadType;
283 0 : return NS_OK;
284 : }
285 :
286 0 : NS_IMETHODIMP nsSHEntry::SetLoadType(PRUint32 aLoadType)
287 : {
288 0 : mLoadType = aLoadType;
289 0 : return NS_OK;
290 : }
291 :
292 0 : NS_IMETHODIMP nsSHEntry::GetID(PRUint32 * aResult)
293 : {
294 0 : *aResult = mID;
295 0 : return NS_OK;
296 : }
297 :
298 0 : NS_IMETHODIMP nsSHEntry::SetID(PRUint32 aID)
299 : {
300 0 : mID = aID;
301 0 : return NS_OK;
302 : }
303 :
304 0 : nsSHEntryShared* nsSHEntry::GetSharedState()
305 : {
306 0 : return mShared;
307 : }
308 :
309 0 : NS_IMETHODIMP nsSHEntry::GetIsSubFrame(bool * aFlag)
310 : {
311 0 : *aFlag = mShared->mIsFrameNavigation;
312 0 : return NS_OK;
313 : }
314 :
315 0 : NS_IMETHODIMP nsSHEntry::SetIsSubFrame(bool aFlag)
316 : {
317 0 : mShared->mIsFrameNavigation = aFlag;
318 0 : return NS_OK;
319 : }
320 :
321 0 : NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult)
322 : {
323 0 : *aResult = mShared->mCacheKey;
324 0 : NS_IF_ADDREF(*aResult);
325 0 : return NS_OK;
326 : }
327 :
328 0 : NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey)
329 : {
330 0 : mShared->mCacheKey = aCacheKey;
331 0 : return NS_OK;
332 : }
333 :
334 0 : NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(bool * aFlag)
335 : {
336 0 : *aFlag = mShared->mSaveLayoutState;
337 0 : return NS_OK;
338 : }
339 :
340 0 : NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(bool aFlag)
341 : {
342 0 : mShared->mSaveLayoutState = aFlag;
343 0 : if (mShared->mLayoutHistoryState) {
344 0 : mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
345 : }
346 :
347 0 : return NS_OK;
348 : }
349 :
350 0 : NS_IMETHODIMP nsSHEntry::GetExpirationStatus(bool * aFlag)
351 : {
352 0 : *aFlag = mShared->mExpired;
353 0 : return NS_OK;
354 : }
355 :
356 0 : NS_IMETHODIMP nsSHEntry::SetExpirationStatus(bool aFlag)
357 : {
358 0 : mShared->mExpired = aFlag;
359 0 : return NS_OK;
360 : }
361 :
362 0 : NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType)
363 : {
364 0 : aContentType = mShared->mContentType;
365 0 : return NS_OK;
366 : }
367 :
368 0 : NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType)
369 : {
370 0 : mShared->mContentType = aContentType;
371 0 : return NS_OK;
372 : }
373 :
374 : NS_IMETHODIMP
375 0 : nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle,
376 : nsIInputStream * aInputStream,
377 : nsILayoutHistoryState * aLayoutHistoryState,
378 : nsISupports * aCacheKey, const nsACString& aContentType,
379 : nsISupports* aOwner,
380 : PRUint64 aDocShellID, bool aDynamicCreation)
381 : {
382 0 : mURI = aURI;
383 0 : mTitle = aTitle;
384 0 : mPostData = aInputStream;
385 :
386 : // Set the LoadType by default to loadHistory during creation
387 0 : mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory;
388 :
389 0 : mShared->mCacheKey = aCacheKey;
390 0 : mShared->mContentType = aContentType;
391 0 : mShared->mOwner = aOwner;
392 0 : mShared->mDocShellID = aDocShellID;
393 0 : mShared->mDynamicallyCreated = aDynamicCreation;
394 :
395 : // By default all entries are set false for subframe flag.
396 : // nsDocShell::CloneAndReplace() which creates entries for
397 : // all subframe navigations, sets the flag to true.
398 0 : mShared->mIsFrameNavigation = false;
399 :
400 : // By default we save LayoutHistoryState
401 0 : mShared->mSaveLayoutState = true;
402 0 : mShared->mLayoutHistoryState = aLayoutHistoryState;
403 :
404 : //By default the page is not expired
405 0 : mShared->mExpired = false;
406 :
407 0 : return NS_OK;
408 : }
409 :
410 : NS_IMETHODIMP
411 0 : nsSHEntry::Clone(nsISHEntry ** aResult)
412 : {
413 0 : *aResult = new nsSHEntry(*this);
414 0 : NS_ADDREF(*aResult);
415 0 : return NS_OK;
416 : }
417 :
418 : NS_IMETHODIMP
419 0 : nsSHEntry::GetParent(nsISHEntry ** aResult)
420 : {
421 0 : NS_ENSURE_ARG_POINTER(aResult);
422 0 : *aResult = mParent;
423 0 : NS_IF_ADDREF(*aResult);
424 0 : return NS_OK;
425 : }
426 :
427 : NS_IMETHODIMP
428 0 : nsSHEntry::SetParent(nsISHEntry * aParent)
429 : {
430 : /* parent not Addrefed on purpose to avoid cyclic reference
431 : * Null parent is OK
432 : *
433 : * XXX this method should not be scriptable if this is the case!!
434 : */
435 0 : mParent = aParent;
436 0 : return NS_OK;
437 : }
438 :
439 : NS_IMETHODIMP
440 0 : nsSHEntry::SetWindowState(nsISupports *aState)
441 : {
442 0 : mShared->mWindowState = aState;
443 0 : return NS_OK;
444 : }
445 :
446 : NS_IMETHODIMP
447 0 : nsSHEntry::GetWindowState(nsISupports **aState)
448 : {
449 0 : NS_IF_ADDREF(*aState = mShared->mWindowState);
450 0 : return NS_OK;
451 : }
452 :
453 : NS_IMETHODIMP
454 0 : nsSHEntry::SetViewerBounds(const nsIntRect &aBounds)
455 : {
456 0 : mShared->mViewerBounds = aBounds;
457 0 : return NS_OK;
458 : }
459 :
460 : NS_IMETHODIMP
461 0 : nsSHEntry::GetViewerBounds(nsIntRect &aBounds)
462 : {
463 0 : aBounds = mShared->mViewerBounds;
464 0 : return NS_OK;
465 : }
466 :
467 : NS_IMETHODIMP
468 0 : nsSHEntry::GetOwner(nsISupports **aOwner)
469 : {
470 0 : NS_IF_ADDREF(*aOwner = mShared->mOwner);
471 0 : return NS_OK;
472 : }
473 :
474 : NS_IMETHODIMP
475 0 : nsSHEntry::SetOwner(nsISupports *aOwner)
476 : {
477 0 : mShared->mOwner = aOwner;
478 0 : return NS_OK;
479 : }
480 :
481 : NS_IMETHODIMP
482 0 : nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry **aEntry)
483 : {
484 0 : NS_ENSURE_ARG_POINTER(aEntry);
485 0 : NS_IF_ADDREF(*aEntry = mShared);
486 0 : return NS_OK;
487 : }
488 :
489 : bool
490 0 : nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry *aEntry)
491 : {
492 0 : return static_cast<nsIBFCacheEntry*>(mShared) == aEntry;
493 : }
494 :
495 : NS_IMETHODIMP
496 0 : nsSHEntry::AdoptBFCacheEntry(nsISHEntry *aEntry)
497 : {
498 0 : nsCOMPtr<nsISHEntryInternal> shEntry = do_QueryInterface(aEntry);
499 0 : NS_ENSURE_STATE(shEntry);
500 :
501 0 : nsSHEntryShared *shared = shEntry->GetSharedState();
502 0 : NS_ENSURE_STATE(shared);
503 :
504 0 : mShared = shared;
505 0 : return NS_OK;
506 : }
507 :
508 : NS_IMETHODIMP
509 0 : nsSHEntry::SharesDocumentWith(nsISHEntry *aEntry, bool *aOut)
510 : {
511 0 : NS_ENSURE_ARG_POINTER(aOut);
512 :
513 0 : nsCOMPtr<nsISHEntryInternal> internal = do_QueryInterface(aEntry);
514 0 : NS_ENSURE_STATE(internal);
515 :
516 0 : *aOut = mShared == internal->GetSharedState();
517 0 : return NS_OK;
518 : }
519 :
520 : NS_IMETHODIMP
521 0 : nsSHEntry::AbandonBFCacheEntry()
522 : {
523 0 : mShared = nsSHEntryShared::Duplicate(mShared);
524 0 : return NS_OK;
525 : }
526 :
527 : //*****************************************************************************
528 : // nsSHEntry: nsISHContainer
529 : //*****************************************************************************
530 :
531 : NS_IMETHODIMP
532 0 : nsSHEntry::GetChildCount(PRInt32 * aCount)
533 : {
534 0 : *aCount = mChildren.Count();
535 0 : return NS_OK;
536 : }
537 :
538 : NS_IMETHODIMP
539 0 : nsSHEntry::AddChild(nsISHEntry * aChild, PRInt32 aOffset)
540 : {
541 0 : if (aChild) {
542 0 : NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
543 : }
544 :
545 0 : if (aOffset < 0) {
546 0 : mChildren.AppendObject(aChild);
547 0 : return NS_OK;
548 : }
549 :
550 : //
551 : // Bug 52670: Ensure children are added in order.
552 : //
553 : // Later frames in the child list may load faster and get appended
554 : // before earlier frames, causing session history to be scrambled.
555 : // By growing the list here, they are added to the right position.
556 : //
557 : // Assert that aOffset will not be so high as to grow us a lot.
558 : //
559 0 : NS_ASSERTION(aOffset < (mChildren.Count()+1023), "Large frames array!\n");
560 :
561 0 : bool newChildIsDyn = false;
562 0 : if (aChild) {
563 0 : aChild->IsDynamicallyAdded(&newChildIsDyn);
564 : }
565 :
566 : // If the new child is dynamically added, try to add it to aOffset, but if
567 : // there are non-dynamically added children, the child must be after those.
568 0 : if (newChildIsDyn) {
569 0 : PRInt32 lastNonDyn = aOffset - 1;
570 0 : for (PRInt32 i = aOffset; i < mChildren.Count(); ++i) {
571 0 : nsISHEntry* entry = mChildren[i];
572 0 : if (entry) {
573 0 : bool dyn = false;
574 0 : entry->IsDynamicallyAdded(&dyn);
575 0 : if (dyn) {
576 0 : break;
577 : } else {
578 0 : lastNonDyn = i;
579 : }
580 : }
581 : }
582 : // InsertObjectAt allows only appending one object.
583 : // If aOffset is larger than Count(), we must first manually
584 : // set the capacity.
585 0 : if (aOffset > mChildren.Count()) {
586 0 : mChildren.SetCount(aOffset);
587 : }
588 0 : if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
589 0 : NS_WARNING("Adding a child failed!");
590 0 : aChild->SetParent(nsnull);
591 0 : return NS_ERROR_FAILURE;
592 : }
593 : } else {
594 : // If the new child isn't dynamically added, it should be set to aOffset.
595 : // If there are dynamically added children before that, those must be
596 : // moved to be after aOffset.
597 0 : if (mChildren.Count() > 0) {
598 0 : PRInt32 start = NS_MIN(mChildren.Count() - 1, aOffset);
599 0 : PRInt32 dynEntryIndex = -1;
600 0 : nsISHEntry* dynEntry = nsnull;
601 0 : for (PRInt32 i = start; i >= 0; --i) {
602 0 : nsISHEntry* entry = mChildren[i];
603 0 : if (entry) {
604 0 : bool dyn = false;
605 0 : entry->IsDynamicallyAdded(&dyn);
606 0 : if (dyn) {
607 0 : dynEntryIndex = i;
608 0 : dynEntry = entry;
609 : } else {
610 0 : break;
611 : }
612 : }
613 : }
614 :
615 0 : if (dynEntry) {
616 0 : nsCOMArray<nsISHEntry> tmp;
617 0 : tmp.SetCount(aOffset - dynEntryIndex + 1);
618 0 : mChildren.InsertObjectsAt(tmp, dynEntryIndex);
619 0 : NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
620 : }
621 : }
622 :
623 :
624 : // Make sure there isn't anything at aOffset.
625 0 : if (aOffset < mChildren.Count()) {
626 0 : nsISHEntry* oldChild = mChildren[aOffset];
627 0 : if (oldChild && oldChild != aChild) {
628 0 : NS_ERROR("Adding a child where we already have a child? This may misbehave");
629 0 : oldChild->SetParent(nsnull);
630 : }
631 : }
632 :
633 0 : if (!mChildren.ReplaceObjectAt(aChild, aOffset)) {
634 0 : NS_WARNING("Adding a child failed!");
635 0 : aChild->SetParent(nsnull);
636 0 : return NS_ERROR_FAILURE;
637 : }
638 : }
639 :
640 0 : return NS_OK;
641 : }
642 :
643 : NS_IMETHODIMP
644 0 : nsSHEntry::RemoveChild(nsISHEntry * aChild)
645 : {
646 0 : NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
647 0 : bool childRemoved = false;
648 0 : bool dynamic = false;
649 0 : aChild->IsDynamicallyAdded(&dynamic);
650 0 : if (dynamic) {
651 0 : childRemoved = mChildren.RemoveObject(aChild);
652 : } else {
653 0 : PRInt32 index = mChildren.IndexOfObject(aChild);
654 0 : if (index >= 0) {
655 0 : childRemoved = mChildren.ReplaceObjectAt(nsnull, index);
656 : }
657 : }
658 0 : if (childRemoved) {
659 0 : aChild->SetParent(nsnull);
660 :
661 : // reduce the child count, i.e. remove empty children at the end
662 0 : for (PRInt32 i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
663 0 : if (!mChildren.RemoveObjectAt(i)) {
664 0 : break;
665 : }
666 : }
667 : }
668 0 : return NS_OK;
669 : }
670 :
671 : NS_IMETHODIMP
672 0 : nsSHEntry::GetChildAt(PRInt32 aIndex, nsISHEntry ** aResult)
673 : {
674 0 : if (aIndex >= 0 && aIndex < mChildren.Count()) {
675 0 : *aResult = mChildren[aIndex];
676 : // yes, mChildren can have holes in it. AddChild's offset parameter makes
677 : // that possible.
678 0 : NS_IF_ADDREF(*aResult);
679 : } else {
680 0 : *aResult = nsnull;
681 : }
682 0 : return NS_OK;
683 : }
684 :
685 : NS_IMETHODIMP
686 0 : nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell)
687 : {
688 0 : NS_ASSERTION(aShell, "Null child shell added to history entry");
689 0 : mShared->mChildShells.AppendObject(aShell);
690 0 : return NS_OK;
691 : }
692 :
693 : NS_IMETHODIMP
694 0 : nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell)
695 : {
696 0 : NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex));
697 0 : return NS_OK;
698 : }
699 :
700 : NS_IMETHODIMP
701 0 : nsSHEntry::ClearChildShells()
702 : {
703 0 : mShared->mChildShells.Clear();
704 0 : return NS_OK;
705 : }
706 :
707 : NS_IMETHODIMP
708 0 : nsSHEntry::GetRefreshURIList(nsISupportsArray **aList)
709 : {
710 0 : NS_IF_ADDREF(*aList = mShared->mRefreshURIList);
711 0 : return NS_OK;
712 : }
713 :
714 : NS_IMETHODIMP
715 0 : nsSHEntry::SetRefreshURIList(nsISupportsArray *aList)
716 : {
717 0 : mShared->mRefreshURIList = aList;
718 0 : return NS_OK;
719 : }
720 :
721 : NS_IMETHODIMP
722 0 : nsSHEntry::SyncPresentationState()
723 : {
724 0 : return mShared->SyncPresentationState();
725 : }
726 :
727 : void
728 0 : nsSHEntry::RemoveFromBFCacheSync()
729 : {
730 0 : mShared->RemoveFromBFCacheSync();
731 0 : }
732 :
733 : void
734 0 : nsSHEntry::RemoveFromBFCacheAsync()
735 : {
736 0 : mShared->RemoveFromBFCacheAsync();
737 0 : }
738 :
739 : nsDocShellEditorData*
740 0 : nsSHEntry::ForgetEditorData()
741 : {
742 : // XXX jlebar Check how this is used.
743 0 : return mShared->mEditorData.forget();
744 : }
745 :
746 : void
747 0 : nsSHEntry::SetEditorData(nsDocShellEditorData* aData)
748 : {
749 0 : NS_ASSERTION(!(aData && mShared->mEditorData),
750 : "We're going to overwrite an owning ref!");
751 0 : if (mShared->mEditorData != aData) {
752 0 : mShared->mEditorData = aData;
753 : }
754 0 : }
755 :
756 : bool
757 0 : nsSHEntry::HasDetachedEditor()
758 : {
759 0 : return mShared->mEditorData != nsnull;
760 : }
761 :
762 : NS_IMETHODIMP
763 0 : nsSHEntry::GetStateData(nsIStructuredCloneContainer **aContainer)
764 : {
765 0 : NS_ENSURE_ARG_POINTER(aContainer);
766 0 : NS_IF_ADDREF(*aContainer = mStateData);
767 0 : return NS_OK;
768 : }
769 :
770 : NS_IMETHODIMP
771 0 : nsSHEntry::SetStateData(nsIStructuredCloneContainer *aContainer)
772 : {
773 0 : mStateData = aContainer;
774 0 : return NS_OK;
775 : }
776 :
777 : NS_IMETHODIMP
778 0 : nsSHEntry::IsDynamicallyAdded(bool* aAdded)
779 : {
780 0 : *aAdded = mShared->mDynamicallyCreated;
781 0 : return NS_OK;
782 : }
783 :
784 : NS_IMETHODIMP
785 0 : nsSHEntry::HasDynamicallyAddedChild(bool* aAdded)
786 : {
787 0 : *aAdded = false;
788 0 : for (PRInt32 i = 0; i < mChildren.Count(); ++i) {
789 0 : nsISHEntry* entry = mChildren[i];
790 0 : if (entry) {
791 0 : entry->IsDynamicallyAdded(aAdded);
792 0 : if (*aAdded) {
793 0 : break;
794 : }
795 : }
796 : }
797 0 : return NS_OK;
798 : }
799 :
800 : NS_IMETHODIMP
801 0 : nsSHEntry::GetDocshellID(PRUint64* aID)
802 : {
803 0 : *aID = mShared->mDocShellID;
804 0 : return NS_OK;
805 : }
806 :
807 : NS_IMETHODIMP
808 0 : nsSHEntry::SetDocshellID(PRUint64 aID)
809 : {
810 0 : mShared->mDocShellID = aID;
811 0 : return NS_OK;
812 : }
813 :
814 :
815 : NS_IMETHODIMP
816 0 : nsSHEntry::GetLastTouched(PRUint32 *aLastTouched)
817 : {
818 0 : *aLastTouched = mShared->mLastTouched;
819 0 : return NS_OK;
820 : }
821 :
822 : NS_IMETHODIMP
823 0 : nsSHEntry::SetLastTouched(PRUint32 aLastTouched)
824 : {
825 0 : mShared->mLastTouched = aLastTouched;
826 0 : return NS_OK;
827 : }
|