File: omnibox_pedal.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (273 lines) | stat: -rw-r--r-- 11,829 bytes parent folder | download | duplicates (7)
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_OMNIBOX_BROWSER_ACTIONS_OMNIBOX_PEDAL_H_
#define COMPONENTS_OMNIBOX_BROWSER_ACTIONS_OMNIBOX_PEDAL_H_

#include <unordered_set>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/omnibox/browser/actions/omnibox_action.h"
#include "components/omnibox/browser/actions/omnibox_pedal_concepts.h"
#include "components/omnibox/browser/buildflags.h"
#include "url/gurl.h"

// Conceptually, a Pedal is a fixed action that can be taken by the user
// pressing a button or taking a new dedicated suggestion when some
// associated intention is detected in an omnibox match suggestion.
// The typical action is to navigate to an internal Chrome surface
// like settings, but other actions like translation or launching
// an incognito window are possible.  The intention is detected by
// checking trigger queries against suggested match queries.
class OmniboxPedal : public OmniboxAction {
 public:
  struct Token {
    // Token identifier from the common token dictionary.
    int id;

    // Index of the next unconsumed token node. Initially this is set to
    // the token's own index, indicating this token is unconsumed. Calls
    // to |TokenSequence::Consume| may then update it to greater values,
    // indicating that this token is consumed.
    size_t link;
  };

  // This is a specialized container for the sequence matching algorithm.
  // It is intended only for single-threaded access by OmniboxPedal classes.
  class TokenSequence {
   public:
    // Construct with reserved size; used when loading real data.
    explicit TokenSequence(size_t reserve_size);

    // Construct with given sequence of |token_ids|; used by tests.
    explicit TokenSequence(std::vector<int> token_ids);

    // Don't use copies. They were necessary with old algorithm,
    // but this structure is amenable to efficient resets on kept instances.
    TokenSequence(const TokenSequence&) = delete;
    TokenSequence& operator=(const TokenSequence&) = delete;
    TokenSequence(TokenSequence&&);
    TokenSequence& operator=(TokenSequence&&);
    ~TokenSequence();

    // Returns true if all tokens are consumed (true for empty sequences).
    bool IsFullyConsumed();

    // Returns the number of unconsumed tokens remaining. Used by tests.
    size_t CountUnconsumed() const;

    // Add token with given |id| to sequence.
    void Add(int id);

    // Clears all tokens from this sequence.
    inline void Clear() { tokens_.clear(); }

    // Initializes all links in sequence to their own index, indicating
    // unconsumed state for all. This is needed after calls to Erase.
    void ResetLinks();

    // Removes one or more instances of |erase_sequence| from this sequence
    // by erasing token items from the |tokens_| container.
    // Returns true if this sequence was changed; false if no match is found.
    bool Erase(const TokenSequence& erase_sequence, bool erase_only_once);

    // Consumes one or more instances of |consume_sequence| from this sequence
    // by updating links on matching tokens. The container is not modified,
    // only its contained elements may be mutated.
    // Returns true if matches were found and consumed; false if no match.
    bool Consume(const TokenSequence& consume_sequence, bool consume_only_once);

    // Returns the total number of tokens, regardless of consumed status.
    inline size_t Size() const { return tokens_.size(); }

    // Returns collection memory estimate for tracing.
    size_t EstimateMemoryUsage() const;

   private:
    // Returns true if this sequence, starting at |index|, matches given
    // |sequence|. The |index_mask| can be used to disregard consumed status (0)
    // or require that all tokens must be unconsumed to match (~0).
    bool MatchesAt(const TokenSequence& sequence,
                   size_t index,
                   size_t index_mask) const;

    // Follows links on tokens starting at |from_index| and returns the first
    // unconsumed index. Returns |Size()| if no unconsumed token is found.
    size_t WalkToUnconsumedIndexFrom(size_t from_index);

    // Storage for tokens.
    std::vector<Token> tokens_;
  };

  struct SynonymGroupSpec {
    bool required;
    bool match_once;
    int message_id;
  };

  class SynonymGroup {
   public:
    // Note: synonyms must be specified in decreasing order by length
    // so that longest matches will be detected first.  For example,
    // "incognito window" must come before "incognito" so that the " window"
    // part will also be covered by this group -- otherwise it would be left
    // intact and wrongly treated as uncovered by the checking algorithm.
    // See OmniboxPedal::IsConceptMatch for the logic that necessitates order.
    SynonymGroup(bool required, bool match_once, size_t reserve_size);
    SynonymGroup(SynonymGroup&&);
    ~SynonymGroup();
    SynonymGroup(const SynonymGroup&) = delete;
    SynonymGroup& operator=(const SynonymGroup&) = delete;
    SynonymGroup& operator=(SynonymGroup&&);

    // Removes one or more matching synonyms from given |remaining| sequence if
    // any are found.  Returns true if checking may continue; false if no more
    // checking is required because what remains cannot be a concept match.
    // Note, if |fully_erase| is true and this method returns true, the
    // |remaining| container has changed structure so ResetLinks must be called.
    // This method doesn't call ResetLinks in that case, for efficiency.
    bool EraseMatchesIn(TokenSequence& remaining, bool fully_erase) const;

    // Add a synonym token sequence to this group.
    void AddSynonym(TokenSequence synonym);

    // When runtime data was preprocessed by pedal_processor,
    // it avoided the need to sort at runtime in Chromium, but with
    // the TC-based l10n technique, data loading needs to be robust
    // enough to handle various forms and orders in translation data.
    // Hence, a call to `SortSynonyms` is required after all calls
    // to `AddSynonym` are complete. We may eliminate this step
    // if we implement post-processing of the .xtb translation files.
    void SortSynonyms();

    // Estimates RAM usage in bytes for this synonym group.
    size_t EstimateMemoryUsage() const;

    // Erases sequences in ignore group from all synonyms in this group.
    void EraseIgnoreGroup(const SynonymGroup& ignore_group);

    // Returns true if this synonym group contains nontrivial data that can
    // be used by the matching algorithm.
    bool IsValid() const;

   protected:
    // If this is true, a synonym of the group must be present for triggering.
    // If false, then presence is simply allowed and does not inhibit triggering
    // (any text not covered by groups would stop trigger).
    bool required_;

    // If this is true, then only the rightmost instance of first synonym found
    // will be taken from text being checked, and additional instances will
    // inhibit trigger because repetition actually changes meaning.  If false,
    // then all instances of all synonyms are taken (repetition is meaningless).
    bool match_once_;

    // The set of interchangeable alternative representations for this group:
    // when trying to clear browsing data, a user may think of 'erase', 'clear',
    // 'delete', etc.  Even though these are not strictly synonymous in natural
    // language, they are considered equivalent within the context of intention
    // to perform this Pedal's action.
    std::vector<TokenSequence> synonyms_;
  };

  OmniboxPedal(OmniboxPedalId id, LabelStrings strings, GURL url);

  // Downcasts the given OmniboxAction to an OmniboxPedal if the supplied
  // instance represents one, otherwise returns nullptr.
  static const OmniboxPedal* FromAction(const OmniboxAction* action);

  // Called after the OmniboxPedalProvider finishes loading all pedals data.
  // This can be used to override implementation bits based on flags, etc.
  virtual void OnLoaded();

  // Sets the destination URL for the Pedal.
  void SetNavigationUrl(const GURL& url);

#if defined(SUPPORT_PEDALS_VECTOR_ICONS)
  // Returns the default vector icon to use for Pedals that do not specify one.
  static const gfx::VectorIcon& GetDefaultVectorIcon();
#endif

  // Add a verbatim token sequence for direct matching.
  // This can improve user experience of omnibox pedals by ensuring that
  // button text entered verbatim is always a sufficient trigger. Since
  // button text labels are not always within the specified set of triggers,
  // it may be possible to discover a pedal, memorize the button
  // label, and then go seeking it out again with the button label, but
  // not find it. With the verbatim sequence, learning a pedal by label will
  // always make the pedal available with that exact input (ignoring case and
  // the common ignore group).
  void AddVerbatimSequence(TokenSequence sequence);

  // Move a synonym group into this Pedal's collection.
  void AddSynonymGroup(SynonymGroup&& group);

  // Specify synonym groups to load from localization strings.
  // `locale_is_english` provides a hint about which locale is being loaded,
  // used to support both synonym-groups and whole-phrase localization.
  virtual std::vector<SynonymGroupSpec> SpecifySynonymGroups(
      bool locale_is_english) const;

  OmniboxPedalId PedalId() const { return id_; }

  // Sometimes pedals report different IDs for metrics, either to enable
  // feature discrimination (e.g. incognito mode) or to unify metrics
  // of closely related pedals (e.g. a ChromeOS specialization of a pedal).
  virtual OmniboxPedalId GetMetricsId() const;

  // If a sufficient set of triggering synonym groups are present in
  // match_sequence then it's a concept match and this returns true.  If a
  // required group is not present, or if match_sequence contains extraneous
  // tokens not covered by any synonym group, then it's not a concept match and
  // this returns false. |match_sequence| is consumed/mutated by this method.
  bool IsConceptMatch(TokenSequence& match_sequence) const;

  // OmniboxAction overrides:
  void RecordActionShown(size_t position, bool executed) const override;
#if defined(SUPPORT_PEDALS_VECTOR_ICONS)
  const gfx::VectorIcon& GetVectorIcon() const override;
#endif
  size_t EstimateMemoryUsage() const override;
  OmniboxActionId ActionId() const override;

#if BUILDFLAG(IS_ANDROID)
  base::android::ScopedJavaLocalRef<jobject> GetOrCreateJavaObject(
      JNIEnv* env) const override;
#endif

 protected:
  FRIEND_TEST_ALL_PREFIXES(OmniboxPedalTest, SynonymGroupErasesFirstMatchOnly);
  FRIEND_TEST_ALL_PREFIXES(OmniboxPedalTest, SynonymGroupsDriveConceptMatches);
  FRIEND_TEST_ALL_PREFIXES(OmniboxPedalTest,
                           VerbatimSynonymGroupDrivesConceptMatches);
  FRIEND_TEST_ALL_PREFIXES(OmniboxPedalImplementationsTest,
                           UnorderedSynonymExpressionsAreConceptMatches);

  ~OmniboxPedal() override;

  OmniboxPedalId id_;

  // Before standard synonym group matching, we can check the verbatim
  // syonym group for direct matches, e.g. with the button label text.
  SynonymGroup verbatim_synonym_group_;

  std::vector<SynonymGroup> synonym_groups_;
};

// This is a simple pedal suitable only for use by tests.
class TestOmniboxPedalClearBrowsingData : public OmniboxPedal {
 public:
  explicit TestOmniboxPedalClearBrowsingData();

  std::vector<SynonymGroupSpec> SpecifySynonymGroups(
      bool locale_is_english) const override;

 protected:
  ~TestOmniboxPedalClearBrowsingData() override = default;
};

#endif  // COMPONENTS_OMNIBOX_BROWSER_ACTIONS_OMNIBOX_PEDAL_H_