summaryrefslogtreecommitdiffstats
path: root/dom/base/HighlightRegistry.h
blob: 87f30e41be161c8a4918d25e5bd6fa94c6719fcc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_HighlightRegistry_h
#define mozilla_dom_HighlightRegistry_h

#include "mozilla/Attributes.h"
#include "mozilla/CompactPair.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include "nsTHashMap.h"
#include "nsHashtablesFwd.h"
#include "nsWrapperCache.h"

class nsFrameSelection;

namespace mozilla {
class ErrorResult;
}
namespace mozilla::dom {

class AbstractRange;
class Document;
class Highlight;

/**
 * @brief HighlightRegistry manages all `Highlight`s available to a `Document`.
 *
 * This class is exposed via `HighlightRegistry.webidl` and used to
 * add or remove `Highlight` instances to a document and binding it
 * to a highlight name.
 *
 * The HighlightRegistry idl interface defines this class to be a `maplike`.
 * To be able to access the members of the maplike without proper support
 * for iteration from C++, the insertion and deletion operations are
 * overridden and the data is also held inside of this class.
 *
 * @see https://drafts.csswg.org/css-highlight-api-1/#registration
 */
class HighlightRegistry final : public nsISupports, public nsWrapperCache {
 public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(HighlightRegistry)

 public:
  explicit HighlightRegistry(Document* aDocument);

 protected:
  ~HighlightRegistry();

 public:
  /**
   * @brief Adds selections for all highlights to the `FrameSelection`.
   *
   * This method is called if highlights are added to the registry before
   * a `FrameSelection` is available.
   */
  MOZ_CAN_RUN_SCRIPT void AddHighlightSelectionsToFrameSelection();

  /**
   * @brief Adds the Range to the Highlight Selection if it belongs to the same
   * Document.
   *
   * If no Highlight Selection for this highlight exists, it will be created.
   * This may occur when a Highlight is added to the Registry after the
   * nsFrameSelection is created.
   */
  MOZ_CAN_RUN_SCRIPT void MaybeAddRangeToHighlightSelection(
      AbstractRange& aRange, Highlight& aHighlight);

  /**
   * @brief Removes the Range from the Highlight Selection if it belongs to the
   * same Document.
   *
   * @note If the last range of a highlight selection is removed, the selection
   * itself is *not* removed.
   */
  MOZ_CAN_RUN_SCRIPT void MaybeRemoveRangeFromHighlightSelection(
      AbstractRange& aRange, Highlight& aHighlight);

  /**
   * @brief Removes the highlight selections associated with the highlight.
   *
   * This method is called when the Highlight is cleared
   * (i.e., all Ranges are removed).
   */
  MOZ_CAN_RUN_SCRIPT void RemoveHighlightSelection(Highlight& aHighlight);

  // WebIDL interface

  Document* GetParentObject() const { return mDocument; };

  JSObject* WrapObject(JSContext* aCx,
                       JS::Handle<JSObject*> aGivenProto) override;

  /**
   * @brief Adds a new `Highlight` to `this` using `aKey` as highlight name.
   *
   * Highlight instances are ordered by insertion.
   *
   * This call registers `this` and `aHighlightName` in the highlight given in
   * `aValue`.
   *
   * If a `FrameSelection` is present, a highlight selection is created.
   */
  MOZ_CAN_RUN_SCRIPT void Set(const nsAString& aKey, Highlight& aValue,
                              ErrorResult& aRv);

  /**
   * @brief Removes all highlights from this registry.
   *
   * If a `FrameSelection` is present, all highlight selections are removed.
   */
  MOZ_CAN_RUN_SCRIPT void Clear(ErrorResult& aRv);

  /**
   * @brief Removes the highlight named `aKey` from the registry.
   *
   * This call removes the combination of `this` and `aKey` from the highlight.
   * If a `FrameSelection` is present, the highlight selection is removed.
   *
   * @return true if `aKey` existed and was deleted.
   */
  MOZ_CAN_RUN_SCRIPT bool Delete(const nsAString& aKey, ErrorResult& aRv);

  /**
   * @brief Get the `FrameSelection` object if available. Can return nullptr.
   */
  RefPtr<nsFrameSelection> GetFrameSelection();

  /**
   * @brief Get the registry name-value tuples.
   */
  nsTArray<CompactPair<RefPtr<nsAtom>, RefPtr<Highlight>>> const&
  HighlightsOrdered() {
    return mHighlightsOrdered;
  }

 private:
  /**
   * Parent document.
   */
  RefPtr<Document> mDocument;

  /**
   * Highlight instances are stored as array of name-value tuples
   * instead of a hashmap in order to preserve the insertion order.
   *
   * This is done
   *    a) to keep the order in sync with the underlying
   *       data structure of the `maplike` interface and
   *    b) because the insertion order defines the stacking order of
   *       of highlights that have the same priority.
   */
  nsTArray<CompactPair<RefPtr<nsAtom>, RefPtr<Highlight>>> mHighlightsOrdered;
};

}  // namespace mozilla::dom

#endif  // mozilla_dom_HighlightRegistry_h