1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 /**
7  * The definitions of objects that make up a history query result set. This file
8  * should only be included by nsNavHistory.h, include that if you want these
9  * classes.
10  */
11 
12 #ifndef nsNavHistoryResult_h_
13 #define nsNavHistoryResult_h_
14 
15 #include "INativePlacesEventCallback.h"
16 #include "nsTArray.h"
17 #include "nsMaybeWeakPtr.h"
18 #include "nsInterfaceHashtable.h"
19 #include "nsDataHashtable.h"
20 #include "nsCycleCollectionParticipant.h"
21 #include "mozilla/storage.h"
22 #include "Helpers.h"
23 
24 class nsNavHistory;
25 class nsNavHistoryQuery;
26 class nsNavHistoryQueryOptions;
27 
28 class nsNavHistoryContainerResultNode;
29 class nsNavHistoryFolderResultNode;
30 class nsNavHistoryQueryResultNode;
31 
32 /**
33  * hashkey wrapper using int64_t KeyType
34  *
35  * @see nsTHashtable::EntryType for specification
36  *
37  * This just truncates the 64-bit int to a 32-bit one for using a hash number.
38  * It is used for bookmark folder IDs, which should be way less than 2^32.
39  */
40 class nsTrimInt64HashKey : public PLDHashEntryHdr {
41  public:
42   typedef const int64_t& KeyType;
43   typedef const int64_t* KeyTypePointer;
44 
nsTrimInt64HashKey(KeyTypePointer aKey)45   explicit nsTrimInt64HashKey(KeyTypePointer aKey) : mValue(*aKey) {}
nsTrimInt64HashKey(const nsTrimInt64HashKey & toCopy)46   nsTrimInt64HashKey(const nsTrimInt64HashKey& toCopy)
47       : mValue(toCopy.mValue) {}
48   ~nsTrimInt64HashKey() = default;
49 
GetKey()50   KeyType GetKey() const { return mValue; }
KeyEquals(KeyTypePointer aKey)51   bool KeyEquals(KeyTypePointer aKey) const { return *aKey == mValue; }
52 
KeyToPointer(KeyType aKey)53   static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
HashKey(KeyTypePointer aKey)54   static PLDHashNumber HashKey(KeyTypePointer aKey) {
55     return static_cast<uint32_t>((*aKey) & UINT32_MAX);
56   }
57   enum { ALLOW_MEMMOVE = true };
58 
59  private:
60   const int64_t mValue;
61 };
62 
63 // Declare methods for implementing nsINavBookmarkObserver
64 // and nsINavHistoryObserver (some methods, such as BeginUpdateBatch overlap)
65 #define NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE(...)                    \
66   NS_DECL_NSINAVBOOKMARKOBSERVER                                       \
67   NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle, \
68                             const nsACString& aGUID) __VA_ARGS__;      \
69   NS_IMETHOD OnFrecencyChanged(nsIURI* aURI, int32_t aNewFrecency,     \
70                                const nsACString& aGUID, bool aHidden,  \
71                                PRTime aLastVisitDate) __VA_ARGS__;     \
72   NS_IMETHOD OnManyFrecenciesChanged() __VA_ARGS__;                    \
73   NS_IMETHOD OnDeleteURI(nsIURI* aURI, const nsACString& aGUID,        \
74                          uint16_t aReason) __VA_ARGS__;                \
75   NS_IMETHOD OnClearHistory() __VA_ARGS__;                             \
76   NS_IMETHOD OnPageChanged(nsIURI* aURI, uint32_t aChangedAttribute,   \
77                            const nsAString& aNewValue,                 \
78                            const nsACString& aGUID) __VA_ARGS__;       \
79   NS_IMETHOD OnDeleteVisits(nsIURI* aURI, bool aPartialRemoval,        \
80                             const nsACString& aGUID, uint16_t aReason, \
81                             uint32_t aTransitionType) __VA_ARGS__;
82 
83 // The internal version is used by query nodes.
84 #define NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL \
85   NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE()
86 
87 // The external version is used by results.
88 #define NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(...) \
89   NS_DECL_BOOKMARK_HISTORY_OBSERVER_BASE(__VA_ARGS__)
90 
91 // nsNavHistoryResult
92 //
93 //    nsNavHistory creates this object and fills in mChildren (by getting
94 //    it through GetTopLevel()). Then FilledAllResults() is called to finish
95 //    object initialization.
96 
97 #define NS_NAVHISTORYRESULT_IID                      \
98   {                                                  \
99     0x455d1d40, 0x1b9b, 0x40e6, {                    \
100       0xa6, 0x41, 0x8b, 0xb7, 0xe8, 0x82, 0x23, 0x87 \
101     }                                                \
102   }
103 
104 class nsNavHistoryResult final
105     : public nsSupportsWeakReference,
106       public nsINavHistoryResult,
107       public nsINavBookmarkObserver,
108       public nsINavHistoryObserver,
109       public mozilla::places::INativePlacesEventCallback {
110  public:
111   NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULT_IID)
112 
113   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
114   NS_DECL_NSINAVHISTORYRESULT
115   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsNavHistoryResult,
116                                            nsINavHistoryResult)
117   NS_DECL_BOOKMARK_HISTORY_OBSERVER_EXTERNAL(override)
118 
119   void AddHistoryObserver(nsNavHistoryQueryResultNode* aNode);
120   void AddBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode,
121                                  int64_t aFolder);
122   void AddAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
123   void AddMobilePrefsObserver(nsNavHistoryQueryResultNode* aNode);
124   void RemoveHistoryObserver(nsNavHistoryQueryResultNode* aNode);
125   void RemoveBookmarkFolderObserver(nsNavHistoryFolderResultNode* aNode,
126                                     int64_t aFolder);
127   void RemoveAllBookmarksObserver(nsNavHistoryQueryResultNode* aNode);
128   void RemoveMobilePrefsObserver(nsNavHistoryQueryResultNode* aNode);
129   void StopObserving();
130 
131   nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
132                    uint32_t aTransitionType, const nsACString& aGUID,
133                    bool aHidden, uint32_t aVisitCount,
134                    const nsAString& aLastKnownTitle);
135 
136  public:
137   explicit nsNavHistoryResult(nsNavHistoryContainerResultNode* mRoot,
138                               const RefPtr<nsNavHistoryQuery>& aQuery,
139                               const RefPtr<nsNavHistoryQueryOptions>& aOptions);
140 
141   RefPtr<nsNavHistoryContainerResultNode> mRootNode;
142 
143   RefPtr<nsNavHistoryQuery> mQuery;
144   RefPtr<nsNavHistoryQueryOptions> mOptions;
145 
146   // One of nsNavHistoryQueryOptions.SORY_BY_* This is initialized to
147   // mOptions.sortingMode, but may be overridden if the user clicks on one of
148   // the columns.
149   uint16_t mSortingMode;
150   // If root node is closed and we try to apply a sortingMode, it would not
151   // work.  So we will apply it when the node will be reopened and populated.
152   // This var states the fact we need to apply sortingMode in such a situation.
153   bool mNeedsToApplySortingMode;
154 
155   // node observers
156   bool mIsHistoryObserver;
157   bool mIsBookmarkFolderObserver;
158   bool mIsAllBookmarksObserver;
159   bool mIsMobilePrefObserver;
160 
161   typedef nsTArray<RefPtr<nsNavHistoryQueryResultNode> > QueryObserverList;
162   QueryObserverList mHistoryObservers;
163   QueryObserverList mAllBookmarksObservers;
164   QueryObserverList mMobilePrefObservers;
165 
166   typedef nsTArray<RefPtr<nsNavHistoryFolderResultNode> > FolderObserverList;
167   nsDataHashtable<nsTrimInt64HashKey, FolderObserverList*>
168       mBookmarkFolderObservers;
169   FolderObserverList* BookmarkFolderObserversForId(int64_t aFolderId,
170                                                    bool aCreate);
171 
172   typedef nsTArray<RefPtr<nsNavHistoryContainerResultNode> >
173       ContainerObserverList;
174 
175   void RecursiveExpandCollapse(nsNavHistoryContainerResultNode* aContainer,
176                                bool aExpand);
177 
178   void InvalidateTree();
179 
180   bool mBatchInProgress;
181 
182   nsMaybeWeakPtrArray<nsINavHistoryResultObserver> mObservers;
183   bool mSuppressNotifications;
184 
185   ContainerObserverList mRefreshParticipants;
186   void requestRefresh(nsNavHistoryContainerResultNode* aContainer);
187 
188   void HandlePlacesEvent(const PlacesEventSequence& aEvents) override;
189 
190   void OnMobilePrefChanged();
191 
192   static void OnMobilePrefChangedCallback(const char* prefName, void* self);
193 
194  protected:
195   virtual ~nsNavHistoryResult();
196 };
197 
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult,NS_NAVHISTORYRESULT_IID)198 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResult, NS_NAVHISTORYRESULT_IID)
199 
200 // nsNavHistoryResultNode
201 //
202 //    This is the base class for every node in a result set. The result itself
203 //    is a node (nsNavHistoryResult inherits from this), as well as every
204 //    leaf and branch on the tree.
205 
206 #define NS_NAVHISTORYRESULTNODE_IID                  \
207   {                                                  \
208     0x54b61d38, 0x57c1, 0x11da, {                    \
209       0x95, 0xb8, 0x00, 0x13, 0x21, 0xc9, 0xf6, 0x9e \
210     }                                                \
211   }
212 
213 // These are all the simple getters, they can be used for the result node
214 // implementation and all subclasses. More complex are GetIcon, GetParent
215 // (which depends on the definition of container result node), and GetUri
216 // (which is overridded for lazy construction for some containers).
217 #define NS_IMPLEMENT_SIMPLE_RESULTNODE                         \
218   NS_IMETHOD GetTitle(nsACString& aTitle) override {           \
219     aTitle = mTitle;                                           \
220     return NS_OK;                                              \
221   }                                                            \
222   NS_IMETHOD GetAccessCount(uint32_t* aAccessCount) override { \
223     *aAccessCount = mAccessCount;                              \
224     return NS_OK;                                              \
225   }                                                            \
226   NS_IMETHOD GetTime(PRTime* aTime) override {                 \
227     *aTime = mTime;                                            \
228     return NS_OK;                                              \
229   }                                                            \
230   NS_IMETHOD GetIndentLevel(int32_t* aIndentLevel) override {  \
231     *aIndentLevel = mIndentLevel;                              \
232     return NS_OK;                                              \
233   }                                                            \
234   NS_IMETHOD GetBookmarkIndex(int32_t* aIndex) override {      \
235     *aIndex = mBookmarkIndex;                                  \
236     return NS_OK;                                              \
237   }                                                            \
238   NS_IMETHOD GetDateAdded(PRTime* aDateAdded) override {       \
239     *aDateAdded = mDateAdded;                                  \
240     return NS_OK;                                              \
241   }                                                            \
242   NS_IMETHOD GetLastModified(PRTime* aLastModified) override { \
243     *aLastModified = mLastModified;                            \
244     return NS_OK;                                              \
245   }                                                            \
246   NS_IMETHOD GetItemId(int64_t* aId) override {                \
247     *aId = mItemId;                                            \
248     return NS_OK;                                              \
249   }
250 
251 // This is used by the base classes instead of
252 // NS_FORWARD_NSINAVHISTORYRESULTNODE(nsNavHistoryResultNode) because they
253 // need to redefine GetType and GetUri rather than forwarding them. This
254 // implements all the simple getters instead of forwarding because they are so
255 // short and we can save a virtual function call.
256 //
257 // (GetUri is redefined only by QueryResultNode and FolderResultNode because
258 // the query might not necessarily be parsed. The rest just return the node's
259 // buffer.)
260 #define NS_FORWARD_COMMON_RESULTNODE_TO_BASE                                  \
261   NS_IMPLEMENT_SIMPLE_RESULTNODE                                              \
262   NS_IMETHOD GetIcon(nsACString& aIcon) override {                            \
263     return nsNavHistoryResultNode::GetIcon(aIcon);                            \
264   }                                                                           \
265   NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) override { \
266     return nsNavHistoryResultNode::GetParent(aParent);                        \
267   }                                                                           \
268   NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) override {        \
269     return nsNavHistoryResultNode::GetParentResult(aResult);                  \
270   }                                                                           \
271   NS_IMETHOD GetTags(nsAString& aTags) override {                             \
272     return nsNavHistoryResultNode::GetTags(aTags);                            \
273   }                                                                           \
274   NS_IMETHOD GetPageGuid(nsACString& aPageGuid) override {                    \
275     return nsNavHistoryResultNode::GetPageGuid(aPageGuid);                    \
276   }                                                                           \
277   NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid) override {            \
278     return nsNavHistoryResultNode::GetBookmarkGuid(aBookmarkGuid);            \
279   }                                                                           \
280   NS_IMETHOD GetVisitId(int64_t* aVisitId) override {                         \
281     return nsNavHistoryResultNode::GetVisitId(aVisitId);                      \
282   }                                                                           \
283   NS_IMETHOD GetFromVisitId(int64_t* aFromVisitId) override {                 \
284     return nsNavHistoryResultNode::GetFromVisitId(aFromVisitId);              \
285   }                                                                           \
286   NS_IMETHOD GetVisitType(uint32_t* aVisitType) override {                    \
287     return nsNavHistoryResultNode::GetVisitType(aVisitType);                  \
288   }
289 
290 class nsNavHistoryResultNode : public nsINavHistoryResultNode {
291  public:
292   nsNavHistoryResultNode(const nsACString& aURI, const nsACString& aTitle,
293                          uint32_t aAccessCount, PRTime aTime);
294 
295   NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYRESULTNODE_IID)
296 
297   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
298   NS_DECL_CYCLE_COLLECTION_CLASS(nsNavHistoryResultNode)
299 
300   NS_IMPLEMENT_SIMPLE_RESULTNODE
301   NS_IMETHOD GetIcon(nsACString& aIcon) override;
302   NS_IMETHOD GetParent(nsINavHistoryContainerResultNode** aParent) override;
303   NS_IMETHOD GetParentResult(nsINavHistoryResult** aResult) override;
304   NS_IMETHOD GetType(uint32_t* type) override {
305     *type = nsNavHistoryResultNode::RESULT_TYPE_URI;
306     return NS_OK;
307   }
308   NS_IMETHOD GetUri(nsACString& aURI) override {
309     aURI = mURI;
310     return NS_OK;
311   }
312   NS_IMETHOD GetTags(nsAString& aTags) override;
313   NS_IMETHOD GetPageGuid(nsACString& aPageGuid) override;
314   NS_IMETHOD GetBookmarkGuid(nsACString& aBookmarkGuid) override;
315   NS_IMETHOD GetVisitId(int64_t* aVisitId) override;
316   NS_IMETHOD GetFromVisitId(int64_t* aFromVisitId) override;
317   NS_IMETHOD GetVisitType(uint32_t* aVisitType) override;
318 
319   virtual void OnRemoving();
320 
321   // Called from result's onItemChanged, see also bookmark observer declaration
322   // in nsNavHistoryFolderResultNode
323   NS_IMETHOD OnItemChanged(int64_t aItemId, const nsACString& aProperty,
324                            bool aIsAnnotationProperty, const nsACString& aValue,
325                            PRTime aNewLastModified, uint16_t aItemType,
326                            int64_t aParentId, const nsACString& aGUID,
327                            const nsACString& aParentGUID,
328                            const nsACString& aOldValue, uint16_t aSource);
329 
330   virtual nsresult OnMobilePrefChanged(bool newValue) { return NS_OK; };
331 
332  protected:
333   virtual ~nsNavHistoryResultNode() = default;
334 
335  public:
336   nsNavHistoryResult* GetResult();
337 
338   // These functions test the type. We don't use a virtual function since that
339   // would take a vtable slot for every one of (potentially very many) nodes.
340   // Note that GetType() already has a vtable slot because its on the iface.
341   bool IsTypeContainer(uint32_t type) {
342     return type == nsINavHistoryResultNode::RESULT_TYPE_QUERY ||
343            type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER ||
344            type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
345   }
346   bool IsContainer() {
347     uint32_t type;
348     GetType(&type);
349     return IsTypeContainer(type);
350   }
351   static bool IsTypeURI(uint32_t type) {
352     return type == nsINavHistoryResultNode::RESULT_TYPE_URI;
353   }
354   bool IsURI() {
355     uint32_t type;
356     GetType(&type);
357     return IsTypeURI(type);
358   }
359   static bool IsTypeFolder(uint32_t type) {
360     return type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER ||
361            type == nsINavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
362   }
363   bool IsFolder() {
364     uint32_t type;
365     GetType(&type);
366     return IsTypeFolder(type);
367   }
368   static bool IsTypeQuery(uint32_t type) {
369     return type == nsINavHistoryResultNode::RESULT_TYPE_QUERY;
370   }
371   bool IsQuery() {
372     uint32_t type;
373     GetType(&type);
374     return IsTypeQuery(type);
375   }
376   bool IsSeparator() {
377     uint32_t type;
378     GetType(&type);
379     return type == nsINavHistoryResultNode::RESULT_TYPE_SEPARATOR;
380   }
381   nsNavHistoryContainerResultNode* GetAsContainer() {
382     NS_ASSERTION(IsContainer(), "Not a container");
383     return reinterpret_cast<nsNavHistoryContainerResultNode*>(this);
384   }
385   nsNavHistoryFolderResultNode* GetAsFolder() {
386     NS_ASSERTION(IsFolder(), "Not a folder");
387     return reinterpret_cast<nsNavHistoryFolderResultNode*>(this);
388   }
389   nsNavHistoryQueryResultNode* GetAsQuery() {
390     NS_ASSERTION(IsQuery(), "Not a query");
391     return reinterpret_cast<nsNavHistoryQueryResultNode*>(this);
392   }
393 
394   RefPtr<nsNavHistoryContainerResultNode> mParent;
395   nsCString mURI;  // not necessarily valid for containers, call GetUri
396   nsCString mTitle;
397   nsString mTags;
398   bool mAreTagsSorted;
399   uint32_t mAccessCount;
400   int64_t mTime;
401   int32_t mBookmarkIndex;
402   int64_t mItemId;
403   int64_t mFolderId;
404   int64_t mVisitId;
405   int64_t mFromVisitId;
406   PRTime mDateAdded;
407   PRTime mLastModified;
408 
409   // The indent level of this node. The root node will have a value of -1.  The
410   // root's children will have a value of 0, and so on.
411   int32_t mIndentLevel;
412 
413   // Frecency of the page.  Valid only for URI nodes.
414   int32_t mFrecency;
415 
416   // Hidden status of the page.  Valid only for URI nodes.
417   bool mHidden;
418 
419   // Transition type used when this node represents a single visit.
420   uint32_t mTransitionType;
421 
422   // Unique Id of the page.
423   nsCString mPageGuid;
424 
425   // Unique Id of the bookmark.
426   nsCString mBookmarkGuid;
427 };
428 
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode,NS_NAVHISTORYRESULTNODE_IID)429 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryResultNode,
430                               NS_NAVHISTORYRESULTNODE_IID)
431 
432 // nsNavHistoryContainerResultNode
433 //
434 //    This is the base class for all nodes that can have children. It is
435 //    overridden for nodes that are dynamically populated such as queries and
436 //    folders. It is used directly for simple containers such as host groups
437 //    in history views.
438 
439 // derived classes each provide their own implementation of has children and
440 // forward the rest to us using this macro
441 #define NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN                           \
442   NS_IMETHOD GetState(uint16_t* _state) override {                            \
443     return nsNavHistoryContainerResultNode::GetState(_state);                 \
444   }                                                                           \
445   NS_IMETHOD GetContainerOpen(bool* aContainerOpen) override {                \
446     return nsNavHistoryContainerResultNode::GetContainerOpen(aContainerOpen); \
447   }                                                                           \
448   NS_IMETHOD SetContainerOpen(bool aContainerOpen) override {                 \
449     return nsNavHistoryContainerResultNode::SetContainerOpen(aContainerOpen); \
450   }                                                                           \
451   NS_IMETHOD GetChildCount(uint32_t* aChildCount) override {                  \
452     return nsNavHistoryContainerResultNode::GetChildCount(aChildCount);       \
453   }                                                                           \
454   NS_IMETHOD GetChild(uint32_t index, nsINavHistoryResultNode** _retval)      \
455       override {                                                              \
456     return nsNavHistoryContainerResultNode::GetChild(index, _retval);         \
457   }                                                                           \
458   NS_IMETHOD GetChildIndex(nsINavHistoryResultNode* aNode, uint32_t* _retval) \
459       override {                                                              \
460     return nsNavHistoryContainerResultNode::GetChildIndex(aNode, _retval);    \
461   }
462 
463 #define NS_NAVHISTORYCONTAINERRESULTNODE_IID         \
464   {                                                  \
465     0x6e3bf8d3, 0x22aa, 0x4065, {                    \
466       0x86, 0xbc, 0x37, 0x46, 0xb5, 0xb3, 0x2c, 0xe8 \
467     }                                                \
468   }
469 
470 class nsNavHistoryContainerResultNode
471     : public nsNavHistoryResultNode,
472       public nsINavHistoryContainerResultNode {
473  public:
474   nsNavHistoryContainerResultNode(const nsACString& aURI,
475                                   const nsACString& aTitle, PRTime aTime,
476                                   uint32_t aContainerType,
477                                   nsNavHistoryQueryOptions* aOptions);
478 
479   virtual nsresult Refresh();
480 
481   NS_DECLARE_STATIC_IID_ACCESSOR(NS_NAVHISTORYCONTAINERRESULTNODE_IID)
482 
483   NS_DECL_ISUPPORTS_INHERITED
484   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsNavHistoryContainerResultNode,
485                                            nsNavHistoryResultNode)
486   NS_FORWARD_COMMON_RESULTNODE_TO_BASE
487   NS_IMETHOD GetType(uint32_t* type) override {
488     *type = mContainerType;
489     return NS_OK;
490   }
491   NS_IMETHOD GetUri(nsACString& aURI) override {
492     aURI = mURI;
493     return NS_OK;
494   }
495   NS_DECL_NSINAVHISTORYCONTAINERRESULTNODE
496 
497  public:
498   virtual void OnRemoving() override;
499 
500   bool AreChildrenVisible();
501 
502   // Overridded by descendents to populate.
503   virtual nsresult OpenContainer();
504   nsresult CloseContainer(bool aSuppressNotifications = false);
505 
506   virtual nsresult OpenContainerAsync();
507 
508   // This points to the result that owns this container. All containers have
509   // their result pointer set so we can quickly get to the result without having
510   // to walk the tree. Yet, this also saves us from storing a million pointers
511   // for every leaf node to the result.
512   RefPtr<nsNavHistoryResult> mResult;
513 
514   // For example, RESULT_TYPE_QUERY. Query and Folder results override GetType
515   // so this is not used, but is still kept in sync.
516   uint32_t mContainerType;
517 
518   // When there are children, this stores the open state in the tree
519   // this is set to the default in the constructor.
520   bool mExpanded;
521 
522   // Filled in by the result type generator in nsNavHistory.
523   nsCOMArray<nsNavHistoryResultNode> mChildren;
524 
525   // mOriginalOptions is the options object used to _define_ this specific
526   // container node. It may differ from mOptions, that is the options used
527   // to _fill_ this container node, because mOptions may be modified by
528   // the direct parent of this container node, see SetAsParentOfNode. For
529   // example, if the parent has excludeItems, options will have it too, even if
530   // originally this object was not defined with that option.
531   RefPtr<nsNavHistoryQueryOptions> mOriginalOptions;
532   RefPtr<nsNavHistoryQueryOptions> mOptions;
533 
534   void FillStats();
535   // Sets this container as parent of aNode, propagating the appropriate
536   // options.
537   void SetAsParentOfNode(nsNavHistoryResultNode* aNode);
538   nsresult ReverseUpdateStats(int32_t aAccessCountChange);
539 
540   // Sorting methods.
541   typedef nsCOMArray<nsNavHistoryResultNode>::TComparatorFunc SortComparator;
542   virtual uint16_t GetSortType();
543 
544   static SortComparator GetSortingComparator(uint16_t aSortType);
545   virtual void RecursiveSort(SortComparator aComparator);
546   uint32_t FindInsertionPoint(nsNavHistoryResultNode* aNode,
547                               SortComparator aComparator, bool* aItemExists);
548   bool DoesChildNeedResorting(uint32_t aIndex, SortComparator aComparator);
549 
550   static int32_t SortComparison_StringLess(const nsAString& a,
551                                            const nsAString& b);
552 
553   static int32_t SortComparison_Bookmark(nsNavHistoryResultNode* a,
554                                          nsNavHistoryResultNode* b,
555                                          void* closure);
556   static int32_t SortComparison_TitleLess(nsNavHistoryResultNode* a,
557                                           nsNavHistoryResultNode* b,
558                                           void* closure);
559   static int32_t SortComparison_TitleGreater(nsNavHistoryResultNode* a,
560                                              nsNavHistoryResultNode* b,
561                                              void* closure);
562   static int32_t SortComparison_DateLess(nsNavHistoryResultNode* a,
563                                          nsNavHistoryResultNode* b,
564                                          void* closure);
565   static int32_t SortComparison_DateGreater(nsNavHistoryResultNode* a,
566                                             nsNavHistoryResultNode* b,
567                                             void* closure);
568   static int32_t SortComparison_URILess(nsNavHistoryResultNode* a,
569                                         nsNavHistoryResultNode* b,
570                                         void* closure);
571   static int32_t SortComparison_URIGreater(nsNavHistoryResultNode* a,
572                                            nsNavHistoryResultNode* b,
573                                            void* closure);
574   static int32_t SortComparison_VisitCountLess(nsNavHistoryResultNode* a,
575                                                nsNavHistoryResultNode* b,
576                                                void* closure);
577   static int32_t SortComparison_VisitCountGreater(nsNavHistoryResultNode* a,
578                                                   nsNavHistoryResultNode* b,
579                                                   void* closure);
580   static int32_t SortComparison_DateAddedLess(nsNavHistoryResultNode* a,
581                                               nsNavHistoryResultNode* b,
582                                               void* closure);
583   static int32_t SortComparison_DateAddedGreater(nsNavHistoryResultNode* a,
584                                                  nsNavHistoryResultNode* b,
585                                                  void* closure);
586   static int32_t SortComparison_LastModifiedLess(nsNavHistoryResultNode* a,
587                                                  nsNavHistoryResultNode* b,
588                                                  void* closure);
589   static int32_t SortComparison_LastModifiedGreater(nsNavHistoryResultNode* a,
590                                                     nsNavHistoryResultNode* b,
591                                                     void* closure);
592   static int32_t SortComparison_TagsLess(nsNavHistoryResultNode* a,
593                                          nsNavHistoryResultNode* b,
594                                          void* closure);
595   static int32_t SortComparison_TagsGreater(nsNavHistoryResultNode* a,
596                                             nsNavHistoryResultNode* b,
597                                             void* closure);
598   static int32_t SortComparison_FrecencyLess(nsNavHistoryResultNode* a,
599                                              nsNavHistoryResultNode* b,
600                                              void* closure);
601   static int32_t SortComparison_FrecencyGreater(nsNavHistoryResultNode* a,
602                                                 nsNavHistoryResultNode* b,
603                                                 void* closure);
604 
605   // finding children: THESE DO NOT ADDREF
606   nsNavHistoryResultNode* FindChildURI(const nsACString& aSpec,
607                                        uint32_t* aNodeIndex);
608   // returns the index of the given node, -1 if not found
609   int32_t FindChild(nsNavHistoryResultNode* aNode) {
610     return mChildren.IndexOf(aNode);
611   }
612 
613   nsNavHistoryResultNode* FindChildByGuid(const nsACString& guid,
614                                           int32_t* nodeIndex);
615 
616   nsresult InsertChildAt(nsNavHistoryResultNode* aNode, int32_t aIndex);
617   nsresult InsertSortedChild(nsNavHistoryResultNode* aNode,
618                              bool aIgnoreDuplicates = false);
619   bool EnsureItemPosition(uint32_t aIndex);
620 
621   nsresult RemoveChildAt(int32_t aIndex);
622 
623   void RecursiveFindURIs(bool aOnlyOne,
624                          nsNavHistoryContainerResultNode* aContainer,
625                          const nsCString& aSpec,
626                          nsCOMArray<nsNavHistoryResultNode>* aMatches);
627   bool UpdateURIs(bool aRecursive, bool aOnlyOne, bool aUpdateSort,
628                   const nsCString& aSpec,
629                   nsresult (*aCallback)(nsNavHistoryResultNode*, const void*,
630                                         const nsNavHistoryResult*),
631                   const void* aClosure);
632   nsresult ChangeTitles(nsIURI* aURI, const nsACString& aNewTitle,
633                         bool aRecursive, bool aOnlyOne);
634 
635  protected:
636   virtual ~nsNavHistoryContainerResultNode();
637 
638   enum AsyncCanceledState { NOT_CANCELED, CANCELED, CANCELED_RESTART_NEEDED };
639 
640   void CancelAsyncOpen(bool aRestart);
641   nsresult NotifyOnStateChange(uint16_t aOldState);
642 
643   nsCOMPtr<mozIStoragePendingStatement> mAsyncPendingStmt;
644   AsyncCanceledState mAsyncCanceledState;
645 };
646 
NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryContainerResultNode,NS_NAVHISTORYCONTAINERRESULTNODE_IID)647 NS_DEFINE_STATIC_IID_ACCESSOR(nsNavHistoryContainerResultNode,
648                               NS_NAVHISTORYCONTAINERRESULTNODE_IID)
649 
650 // nsNavHistoryQueryResultNode
651 //
652 //    Overridden container type for complex queries over history and/or
653 //    bookmarks. This keeps itself in sync by listening to history and
654 //    bookmark notifications.
655 
656 class nsNavHistoryQueryResultNode final
657     : public nsNavHistoryContainerResultNode,
658       public nsINavHistoryQueryResultNode,
659       public nsINavBookmarkObserver {
660  public:
661   nsNavHistoryQueryResultNode(const nsACString& aTitle, PRTime aTime,
662                               const nsACString& aQueryURI,
663                               const RefPtr<nsNavHistoryQuery>& aQuery,
664                               const RefPtr<nsNavHistoryQueryOptions>& aOptions);
665 
666   NS_DECL_ISUPPORTS_INHERITED
667   NS_FORWARD_COMMON_RESULTNODE_TO_BASE
668   NS_IMETHOD GetType(uint32_t* type) override {
669     *type = nsNavHistoryResultNode::RESULT_TYPE_QUERY;
670     return NS_OK;
671   }
672   NS_IMETHOD GetUri(nsACString& aURI) override;  // does special lazy creation
673   NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
674   NS_IMETHOD GetHasChildren(bool* aHasChildren) override;
675   NS_DECL_NSINAVHISTORYQUERYRESULTNODE
676 
677   virtual nsresult OnMobilePrefChanged(bool newValue) override;
678 
679   bool CanExpand();
680   bool IsContainersQuery();
681 
682   virtual nsresult OpenContainer() override;
683 
684   NS_DECL_BOOKMARK_HISTORY_OBSERVER_INTERNAL
685 
686   nsresult OnItemAdded(int64_t aItemId, int64_t aParentId, int32_t aIndex,
687                        uint16_t aItemType, nsIURI* aURI, PRTime aDateAdded,
688                        const nsACString& aGUID, const nsACString& aParentGUID,
689                        uint16_t aSource);
690 
691   nsresult OnItemRemoved(int64_t aItemId, int64_t aParentFolder, int32_t aIndex,
692                          uint16_t aItemType, nsIURI* aURI,
693                          const nsACString& aGUID, const nsACString& aParentGUID,
694                          uint16_t aSource);
695 
696   // The internal version has an output aAdded parameter, it is incremented by
697   // query nodes when the visited uri belongs to them. If no such query exists,
698   // the history result creates a new query node dynamically.
699   nsresult OnVisit(nsIURI* aURI, int64_t aVisitId, PRTime aTime,
700                    uint32_t aTransitionType, bool aHidden, uint32_t* aAdded);
701   virtual void OnRemoving() override;
702 
703  public:
704   RefPtr<nsNavHistoryQuery> mQuery;
705   uint32_t mLiveUpdate;  // one of QUERYUPDATE_* in nsNavHistory.h
706   bool mHasSearchTerms;
707 
708   // safe options getter, ensures query is parsed
709   nsNavHistoryQueryOptions* Options();
710 
711   // this indicates whether the query contents are valid, they don't go away
712   // after the container is closed until a notification comes in
713   bool mContentsValid;
714 
715   nsresult FillChildren();
716   void ClearChildren(bool unregister);
717   nsresult Refresh() override;
718 
719   virtual uint16_t GetSortType() override;
720   virtual void RecursiveSort(SortComparator aComparator) override;
721 
722   nsresult NotifyIfTagsChanged(nsIURI* aURI);
723 
724   uint32_t mBatchChanges;
725 
726   // Tracks transition type filters.
727   nsTArray<uint32_t> mTransitions;
728 
729  protected:
730   virtual ~nsNavHistoryQueryResultNode();
731 };
732 
733 // nsNavHistoryFolderResultNode
734 //
735 //    Overridden container type for bookmark folders. It will keep the contents
736 //    of the folder in sync with the bookmark service.
737 
738 class nsNavHistoryFolderResultNode final
739     : public nsNavHistoryContainerResultNode,
740       public nsINavHistoryQueryResultNode,
741       public nsINavBookmarkObserver,
742       public mozilla::places::WeakAsyncStatementCallback {
743  public:
744   nsNavHistoryFolderResultNode(const nsACString& aTitle,
745                                nsNavHistoryQueryOptions* options,
746                                int64_t aFolderId);
747 
748   NS_DECL_ISUPPORTS_INHERITED
749   NS_FORWARD_COMMON_RESULTNODE_TO_BASE
GetType(uint32_t * type)750   NS_IMETHOD GetType(uint32_t* type) override {
751     if (mTargetFolderItemId != mItemId) {
752       *type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER_SHORTCUT;
753     } else {
754       *type = nsNavHistoryResultNode::RESULT_TYPE_FOLDER;
755     }
756     return NS_OK;
757   }
758   NS_IMETHOD GetUri(nsACString& aURI) override;
759   NS_FORWARD_CONTAINERNODE_EXCEPT_HASCHILDREN
760   NS_IMETHOD GetHasChildren(bool* aHasChildren) override;
761   NS_DECL_NSINAVHISTORYQUERYRESULTNODE
762 
763   virtual nsresult OpenContainer() override;
764 
765   virtual nsresult OpenContainerAsync() override;
766   NS_DECL_ASYNCSTATEMENTCALLBACK
767 
768   // This object implements a bookmark observer interface. This is called from
769   // the result's actual observer and it knows all observers are
770   // FolderResultNodes
771   NS_DECL_NSINAVBOOKMARKOBSERVER
772 
773   nsresult OnItemAdded(int64_t aItemId, int64_t aParentId, int32_t aIndex,
774                        uint16_t aItemType, nsIURI* aURI, PRTime aDateAdded,
775                        const nsACString& aGUID, const nsACString& aParentGUID,
776                        uint16_t aSource);
777   nsresult OnItemRemoved(int64_t aItemId, int64_t aParentFolder, int32_t aIndex,
778                          uint16_t aItemType, nsIURI* aURI,
779                          const nsACString& aGUID, const nsACString& aParentGUID,
780                          uint16_t aSource);
781   virtual void OnRemoving() override;
782 
783   // this indicates whether the folder contents are valid, they don't go away
784   // after the container is closed until a notification comes in
785   bool mContentsValid;
786 
787   // If the node is generated from a place:folder=X query, this is the target
788   // folder id and GUID.  For regular folder nodes, they are set to the same
789   // values as mItemId and mBookmarkGuid. For more complex queries, they are set
790   // to -1/an empty string.
791   int64_t mTargetFolderItemId;
792   nsCString mTargetFolderGuid;
793 
794   nsresult FillChildren();
795   void ClearChildren(bool aUnregister);
796   nsresult Refresh() override;
797 
798   bool StartIncrementalUpdate();
799   void ReindexRange(int32_t aStartIndex, int32_t aEndIndex, int32_t aDelta);
800 
801   nsNavHistoryResultNode* FindChildById(int64_t aItemId, uint32_t* aNodeIndex);
802 
803  protected:
804   virtual ~nsNavHistoryFolderResultNode();
805 
806  private:
807   nsresult OnChildrenFilled();
808   void EnsureRegisteredAsFolderObserver();
809   nsresult FillChildrenAsync();
810 
811   bool mIsRegisteredFolderObserver;
812   int32_t mAsyncBookmarkIndex;
813 };
814 
815 // nsNavHistorySeparatorResultNode
816 //
817 // Separator result nodes do not hold any data.
818 class nsNavHistorySeparatorResultNode : public nsNavHistoryResultNode {
819  public:
820   nsNavHistorySeparatorResultNode();
821 
GetType(uint32_t * type)822   NS_IMETHOD GetType(uint32_t* type) override {
823     *type = nsNavHistoryResultNode::RESULT_TYPE_SEPARATOR;
824     return NS_OK;
825   }
826 };
827 
828 #endif  // nsNavHistoryResult_h_
829