• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WEB_DATA_DETECTOR_ADAPTER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WEB_DATA_DETECTOR_ADAPTER_H
18 
19 #include <list>
20 #include <unordered_map>
21 #include <mutex>
22 
23 #include "interfaces/inner_api/ace/ai/data_detector_interface.h"
24 
25 #include "base/memory/ace_type.h"
26 #include "base/memory/referenced.h"
27 #include "core/components/web/web_property.h"
28 
29 namespace OHOS::Ace::NG {
30 
31 struct NodeData {
32     std::string path;
33     std::string text;
34 };
35 
36 struct EntityMatch {
37     size_t start; // u16
38     size_t end; // u16
39     std::string entityType;
40     std::string clean;
41     std::map<std::string, std::string> params;
42 };
43 
44 struct WebDataDetectorConfig {
45     bool enable;
46     bool enablePreview;
47     std::string types;
48     std::string color;
49     std::string textDecorationStyle;
50 };
51 
52 struct AIMenuInfo {
53     std::string entityType;
54     std::string content;
55     std::string outerHTML;
56     RectF rect; // refer to web
57 };
58 
59 const size_t MAX_CACHE_SIZE = 100;
60 const size_t MAX_SELECTED_TEXT_SIZE = 255;
61 
62 using DataDetectorResult = std::vector<EntityMatch>; // for single node
63 
64 enum class AISupportStatus {
65     UNKNOWN = 0,
66     UNSUPPORTED,
67     SUPPORTED,
68 };
69 
70 struct DataDetectorRequestData {
71     std::string requestId;
72     std::vector<NodeData> nodes;
73     std::vector<size_t> detectIds;
74     std::vector<std::pair<size_t, size_t> > detectOffsets;
75     std::vector<DataDetectorResult> matches;
76 };
77 
78 template <typename KeyType, typename ValueType>
79 class WebDataDetectorCache : public AceType {
80     DECLARE_ACE_TYPE(WebDataDetectorCache, AceType);
81 public:
WebDataDetectorCache(size_t maxSize)82     explicit WebDataDetectorCache(size_t maxSize) : maxSize_(maxSize) {}
83 
Get(const KeyType & key,ValueType & outValue)84     bool Get(const KeyType& key, ValueType& outValue)
85     {
86         std::lock_guard<std::mutex> lock(mutex_);
87         auto it = cacheMap_.find(key);
88         if (it == cacheMap_.end()) {
89             return false;
90         }
91 
92         accessQueue_.splice(accessQueue_.begin(), accessQueue_, it->second.queueIt);
93         outValue = it->second.value;
94         return true;
95     }
96 
Put(const KeyType & key,const ValueType & value)97     void Put(const KeyType& key, const ValueType& value)
98     {
99         std::lock_guard<std::mutex> lock(mutex_);
100 
101         auto it = cacheMap_.find(key);
102         if (it != cacheMap_.end()) {
103             it->second.value = value;
104             accessQueue_.splice(accessQueue_.begin(), accessQueue_, it->second.queueIt);
105             return;
106         }
107 
108         accessQueue_.push_front(key);
109         cacheMap_[key] = {value, accessQueue_.begin()};
110 
111         if (cacheMap_.size() > maxSize_) {
112             cacheMap_.erase(accessQueue_.back());
113             accessQueue_.pop_back();
114         }
115     }
116 
117 private:
118     struct CacheNode {
119         ValueType value;
120         typename std::list<KeyType>::iterator queueIt;
121     };
122 
123     std::unordered_map<KeyType, CacheNode> cacheMap_;
124     std::list<KeyType> accessQueue_;
125     size_t maxSize_;
126     std::mutex mutex_;
127 };
128 
129 class WebDataDetectorAdapter : public AceType {
130     DECLARE_ACE_TYPE(WebDataDetectorAdapter, AceType);
131 
132 public:
133     explicit WebDataDetectorAdapter(const WeakPtr<Pattern>& pattern, size_t cacheSize = 100);
134     ~WebDataDetectorAdapter() override = default;
135 
SetPattern(const WeakPtr<Pattern> & pattern)136     void SetPattern(const WeakPtr<Pattern>& pattern)
137     {
138         pattern_ = pattern;
139     }
140 
GetDataDetectorEnable()141     bool GetDataDetectorEnable()
142     {
143         return config_.enable;
144     }
145 
GetDataDetectorEnablePrewiew()146     bool GetDataDetectorEnablePrewiew()
147     {
148         return config_.enablePreview;
149     }
150 
151     void SetDataDetectorEnable(bool enable);
152     void SetDataDetectorConfig(const TextDetectConfig& config);
153     void Init();
154     void InitJSProxy();
155     void ReleaseJSProxy();
156     void SetNWebConfig();
157 
158     void ProcessRequest(const std::string& jsonStr);
159 
160     std::string PrepareDetectText(const std::string& requestId);
161     void SendRequestToAI(const std::string& requestId);
162     void ParseAIResultByType(std::shared_ptr<DataDetectorRequestData>& requestContext, const std::string& detectType,
163         const std::unique_ptr<JsonValue>& jsonValue);
164     void HandleResultFromAI(const std::string& requestId, const TextDataDetectResult& result);
165     std::string GetResultJsonString(const std::string& requestId);
166     void SendResultToJS(const std::string& resultStr);
167 
168     std::map<std::string, std::string> AttrsToParams(const std::unique_ptr<JsonValue>& jsonValue);
169 
170     static std::map<std::string, std::string> ParseExtraParams(
171         const std::string& detectType, const std::unique_ptr<JsonValue>& item);
172     static int32_t MatchInOffsets(EntityMatch& match, const std::vector<std::pair<size_t, size_t> >& detectOffsets);
173 
174     void ProcessClick(const std::string& jsonStr);
175     void InitAIMenu();
176     void GetAIMenu();
177     bool IsAISupported();
178     RectF CalcAIMenuRect(double left, double top, double right, double bottom);
179     bool GetAIMenuOptions(
180         const AIMenuInfo& info, std::vector<std::pair<std::string, std::function<void()>>>& menuOptions);
181     bool ShowAIMenu(const AIMenuInfo& info);
182     void OnClickAIMenuOption(const AIMenuInfo& info, const std::pair<std::string, FuncVariant>& menuOption);
183     void OnClickMenuItem(const std::string& action, const AIMenuInfo& info);
184 
185     void OnClickAISelectMenuOption(TextDataDetectType type, const std::string& content);
186     void DetectSelectedText(const std::string& text);
187     static DataDetectorResult ParseAIResultJson(std::unique_ptr<JsonValue>& jsonValue);
188     void OnDetectSelectedTextDone(const TextDataDetectResult& result);
189     void UpdateAISelectMenu(const std::string& entityType, const std::string& content);
190 
191     static std::string ReplaceARGBToRGBA(const std::string& text);
192     static std::string UrlDecode(const std::string& str);
193     bool SetPreviewMenuLink(const std::string& link);
194     bool GetPreviewMenuBuilder(std::function<void()>& menuBuilder, std::function<void()>& previewBuilder);
195     std::string GetLinkOuterHTML(const std::string& entityType, const std::string& content);
196     std::function<void()> GetPreviewMenuOptionCallback(TextDataDetectType type, const std::string& content);
197     RefPtr<FrameNode> GetPreviewMenuNode(const AIMenuInfo& info);
198 
199     void SetPreviewMenuAttr(TextDataDetectType type = TextDataDetectType::INVALID, const std::string& content = "",
200         const std::map<std::string, std::string>& params = {});
201 
202     static TextDataDetectType ConvertTypeFromString(const std::string& type);
203 
204     void CloseAIMenu();
205     void CloseOtherMenu();
206 
207     void AIPostTask(const std::function<void()>& task, TaskExecutor::TaskType taskType, const std::string& name,
208         uint32_t delay = 0);
209     bool SetRequestContext(const std::string& requestId, DataDetectorRequestData&& requestData);
210     bool RemoveRequestContext(const std::string& requestId);
211     void ResetContextMap();
212     std::shared_ptr<DataDetectorRequestData> GetRequestContext(const std::string& requestId);
213 
214 private:
215 
216     WeakPtr<Pattern> pattern_;
217 
218     // properties
219     WebDataDetectorConfig config_ { false, false, "", "", "" };
220     WebDataDetectorConfig newConfig_ { false, false, "", "", "" };
221     bool hasInit_ = false;
222 
223     bool initDataDetectorProxy_ = false;
224 
225     // preview menu
226     TextDataDetectType previewMenuType_ = TextDataDetectType::INVALID;
227     std::string previewMenuContent_ = "";
228     std::map<std::string, std::string> previewMenuExtraParams_;
229     std::unordered_set<std::string> extraParamKeys_;
230 
231     // cache
232     RefPtr<WebDataDetectorCache<std::string, DataDetectorResult>> resultCache_ = nullptr;
233 
234     // request context
235     std::mutex contextMutex_;
236     std::unordered_map<std::string, std::shared_ptr<DataDetectorRequestData> > contextMap_;
237 
238     // ai menu
239     TextDataDetectResult textDetectResult_;
240     bool initAIMenu_ = false;
241     AISupportStatus aiSupportStatus_ = AISupportStatus::UNKNOWN;
242 };
243 
244 } // namespace OHOS::Ace
245 
246 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_WEB_DATA_DETECTOR_ADAPTER_H