Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / base / TextDirectiveCreator.h
blob5c525473c271d5ee32ffae65ef65a6c280276370
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef DOM_TEXTDIRECTIVECREATOR_H_
8 #define DOM_TEXTDIRECTIVECREATOR_H_
10 #include <tuple>
11 #include "RangeBoundary.h"
12 #include "nsStringFwd.h"
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/Result.h"
16 class nsRange;
18 namespace mozilla {
19 class ErrorResult;
22 namespace mozilla::dom {
23 class Document;
25 class RangeContentCache {
26 public:
27 /** Get fold string representation of a pair of two ranges.
29 * If the fold case string for a range is not yet available in the cache, it
30 * is created using `TextDirectiveUtil::RangeContentAsFoldCase()` and inserted
31 * into the cache. Because inserting into the cache might reallocate the
32 * cache, the lifetime of the returned objects is bound by calls to `Get()`.
34 * Due to the nature of the current use cases, this method accepts two ranges
35 * and returns a tuple of two strings.
37 * This method is safe to be called with any of the input ranges being
38 * `nullptr`. In that case, the returned string will be empty.
40 Result<std::tuple<const nsString&, const nsString&>, ErrorResult> Get(
41 nsRange* aRange1, nsRange* aRange2);
43 private:
44 nsTHashMap<nsRange*, nsString> mCache;
47 /**
48 * @brief Helper which represents a potential text directive using `nsRange`s.
50 * In addition to the _current_ context terms of the text directive, it also
51 * contains the _fully expanded_ context terms, i.e. the ranges until the next
52 * block boundary.
54 * `TextDirectiveCandidate`s are immutable.
55 * This allows sharing `nsRange`s across instances to save memory. Also, this
56 * allows to create the text directive string representation
57 * (`TextDirectiveString()`) once when the object is created.
58 * However, the `nsRange` members cannot be marked as `const`:
59 * - It's not possible to have the `nsRange` itself be const because
60 * `nsRange::ToString()` is not const.
61 * - It's not possible to have the `RefPtr` be const because of move semantics.
63 class TextDirectiveCandidate {
64 public:
65 TextDirectiveCandidate(TextDirectiveCandidate&&) = default;
66 TextDirectiveCandidate& operator=(TextDirectiveCandidate&&) = default;
67 TextDirectiveCandidate(const TextDirectiveCandidate&) = delete;
68 TextDirectiveCandidate& operator=(const TextDirectiveCandidate&) = delete;
70 /**
71 * @brief Creates a candidate from a given input range.
73 * This function determines whether the candidate needs to use exact or
74 * range-based matching based on whether the input range contains a block
75 * boundary.
76 * Then, it determines the fully-expanded ranges for all context terms and
77 * creates an instance.
79 * @param aInputRange The input range.
80 * @return A text directive candidate, or an error.
82 static Result<TextDirectiveCandidate, ErrorResult> CreateFromInputRange(
83 const nsRange* aInputRange);
85 static Result<TextDirectiveCandidate, ErrorResult> CreateFromStartAndEndRange(
86 const nsRange* aStartRange, const nsRange* aEndRange);
88 /**
89 * Creates new text directive candidates for each element of `aMatches`, which
90 * eliminate the element.
92 * @see CreateNewCandidatesForGivenMatch()
94 Result<nsTArray<TextDirectiveCandidate>, ErrorResult>
95 CreateNewCandidatesForMatches(
96 const nsTArray<const TextDirectiveCandidate*>& aMatches,
97 RangeContentCache& aRangeContentCache);
99 /**
100 * Creates new text directive candidates which eliminate `aOther` by extending
101 * context terms in every direction.
103 * If exact matching is used, this function will create up to two new
104 * candidates, one where the prefix is extended until it is not matching with
105 * other, one where suffix is extended.
106 * If range based matching is used, there will be additional candidates
107 * created which extend the start and end term.
109 * If even a fully expanded context term is matching the context term of
110 * `other`, no candidate is created.
111 * Returning an empty array indicates that it is not possible to create a text
112 * directive for the given text in the current document, because it is not
113 * possible to create a text directive that would not match `other`.
115 Result<nsTArray<TextDirectiveCandidate>, ErrorResult>
116 CreateNewCandidatesForGivenMatch(const TextDirectiveCandidate& aOther,
117 RangeContentCache& aRangeContentCache) const;
120 * Clones `this` and replaces ranges which are non-null.
121 * The parameter ranges are moved into the function to emphasize that the
122 * objects are not cloned. Therefore, the ranges must not be updated after
123 * this call.
125 Result<TextDirectiveCandidate, ErrorResult> CloneWith(
126 RefPtr<nsRange>&& aNewPrefixRange, RefPtr<nsRange>&& aNewStartRange,
127 RefPtr<nsRange>&& aNewEndRange, RefPtr<nsRange>&& aNewSuffixRange) const;
130 * @brief Returns true if the text directive string in `this` would match the
131 * other candidate.
133 * The candidate matches another candidate if the context terms are fully
134 * present in the fully-expanded context terms of the other candidate.
136 Result<bool, ErrorResult> ThisCandidateMatchesOther(
137 const TextDirectiveCandidate& aOther,
138 RangeContentCache& aRangeContentCache) const;
141 * @brief Returns a filtered list of candidates, which still match against
142 * `this`.
144 * This method uses `ThisCandidateMatchesOther()` to check whether a candidate
145 * is still matching against `this` or can be ruled out.
147 nsTArray<const TextDirectiveCandidate*> FilterNonMatchingCandidates(
148 const nsTArray<const TextDirectiveCandidate*>& aMatches,
149 RangeContentCache& aRangeContentCache);
151 /** Returns true if the candidate uses exact matching (and not range-based) */
152 bool UseExactMatch() const { return !mEndRange; }
154 nsRange* StartRange() { return mStartRange; }
155 const nsRange* StartRange() const { return mStartRange; }
157 nsRange* EndRange() { return mEndRange; }
158 const nsRange* EndRange() const { return mEndRange; }
161 * @brief Returns a percent-encoded text directive string representation of
162 * this candidate.
164 const nsCString& TextDirectiveString() const;
167 * Logging utility. This function outputs the current state, ie. the text
168 * directive string, the context term range contents, the fully expanded
169 * context terms, and a fully expanded text directive string.
171 void LogCurrentState(const char* aCallerFunc) const;
173 private:
174 TextDirectiveCandidate(nsRange* aStartRange, nsRange* aFullStartRange,
175 nsRange* aEndRange, nsRange* aFullEndRange,
176 nsRange* aPrefixRange, nsRange* aFullPrefixRange,
177 nsRange* aSuffixRange, nsRange* aFullSuffixRange);
180 * @brief Creates a range which starts at the beginning of `aRange` and ends
181 * at the first block boundary inside of `aRange`.
183 * @return nullptr if `aRange` does not contain a block boundary.
185 static Result<RefPtr<nsRange>, ErrorResult>
186 MaybeCreateStartToBlockBoundaryRange(const nsRange& aRange);
189 * @brief Creates a range which starts at the last block boundary in `aRange`
190 * and ends at `aRange`s end.
192 * @return nullptr if `aRange` does not contain a block boundary.
194 static Result<RefPtr<nsRange>, ErrorResult>
195 MaybeCreateEndToBlockBoundaryRange(const nsRange& aRange);
198 * @brief Creates the collapsed and fully expanded prefix ranges.
200 * The created ranges _end_ at `aRangeBoundary`. The first returned element is
201 * collapsed to `aRangeBoundary`, the second one is expanded to the nearest
202 * block boundary to the left.
204 * @param aRangeBoundary The end point of the created ranges.
205 * @return The first element is the collapsed range, the second one is the
206 * fully expanded range.
208 static Result<std::tuple<RefPtr<nsRange>, RefPtr<nsRange>>, ErrorResult>
209 CreatePrefixRanges(const RangeBoundary& aRangeBoundary);
212 * @brief Creates the collapsed and fully expanded suffix ranges.
214 * The created ranges _start_ at `aRangeBoundary`. The first returned element
215 * is collapsed to `aRangeBoundary`, the second one is expanded to the nearest
216 * block boundary to the right.
218 * @param aRangeBoundary The start point of the created ranges.
219 * @return The first element is the collapsed range, the second one is the
220 * fully expanded range.
222 static Result<std::tuple<RefPtr<nsRange>, RefPtr<nsRange>>, ErrorResult>
223 CreateSuffixRanges(const RangeBoundary& aRangeBoundary);
226 * @brief Creates a percent-encoded string representation of the candidate.
229 Result<Ok, ErrorResult> CreateTextDirectiveString();
231 RefPtr<nsRange> mStartRange;
232 RefPtr<nsRange> mFullStartRange;
233 RefPtr<nsRange> mEndRange;
234 RefPtr<nsRange> mFullEndRange;
236 RefPtr<nsRange> mPrefixRange;
237 RefPtr<nsRange> mFullPrefixRange;
238 RefPtr<nsRange> mSuffixRange;
239 RefPtr<nsRange> mFullSuffixRange;
241 nsCString mTextDirectiveString;
245 * @brief Helper class to create a text directive string from a given `nsRange`.
247 * The class provides a public static creator function which encapsulates all
248 * necessary logic. The class itself stores necessary state throughout the
249 * steps.
251 class TextDirectiveCreator final {
252 public:
254 * @brief Static creator function. Takes an `nsRange` and creates a text
255 * directive string, if possible.
257 * @param aDocument The document in which `aInputRange` lives.
258 * @param aInputRange The input range. This range will not be modified.
260 * @return Returns a percent-encoded text directive string on success, an
261 * empty string if it's not possible to create a text fragment for the
262 * given range, or an error code.
264 static Result<nsCString, ErrorResult> CreateTextDirectiveFromRange(
265 Document& aDocument, nsRange* aInputRange);
267 private:
268 TextDirectiveCreator(Document& aDocument, nsRange* aInputRange,
269 TextDirectiveCandidate&& aTextDirective);
271 * Find all ranges up to the end of the target range that have the same
272 * content. The input range will *not* be part of the result, therefore an
273 * empty array indicates that there are no conflicts and the text directive
274 * can be constructed trivially.
276 Result<nsTArray<TextDirectiveCandidate>, ErrorResult>
277 FindAllMatchingCandidates();
280 * @brief Find all occurrences of `aSearchQuery` in the partial document.
282 * This method uses `nsFind` to perform a case-insensitive search for
283 * `aSearchQuery` in the document up to the end of `mInputRange`. It is not
284 * necessary to continue searching after the end of our input range.
286 * @return List of `nsRange`s which have the case-insensitive-same content as
287 * `mInputRange`.
289 Result<nsTArray<RefPtr<nsRange>>, ErrorResult> FindAllMatchingRanges(
290 const nsString& aSearchQuery);
292 Result<nsCString, ErrorResult> CreateTextDirectiveFromMatches(
293 const nsTArray<TextDirectiveCandidate>& aTextDirectiveMatches);
295 Document& mDocument;
296 RefPtr<nsRange> mInputRange;
297 TextDirectiveCandidate mTextDirective;
298 RangeContentCache mRangeContentCache;
300 } // namespace mozilla::dom
301 #endif