1 /*
2 * Copyright (c) 2021 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 #include "frameworks/bridge/test/unittest/jsfrontend/dom_node_factory.h"
17
18 #include <map>
19
20 #include "gtest/gtest.h"
21
22 #include "base/json/json_util.h"
23 #include "base/log/log.h"
24 #include "base/utils/utils.h"
25 #include "core/components/declaration/common/declaration.h"
26 #include "core/components/theme/theme_manager_impl.h"
27 #include "frameworks/bridge/common/dom/dom_document.h"
28 #include "frameworks/bridge/test/unittest/jsfrontend/dom_mock.h"
29 #include "frameworks/bridge/test/unittest/jsfrontend/dom_test_constants.h"
30
31 namespace OHOS::Ace::Framework {
32 namespace {
33
34 const std::map<std::string, const std::vector<std::string>&> DOMSTYLELIST = {
35 { DOM_NODE_TAG_DIV, DIV_STYLE_LIST },
36 { DOM_NODE_TAG_TEXT, TEXT_STYLE_LIST },
37 { DOM_NODE_TAG_PROGRESS, PROGRESS_STYLE_LIST },
38 { DOM_NODE_TAG_SLIDER, SLIDER_STYLE_LIST },
39 { DOM_NODE_TAG_SWIPER, SWIPER_STYLE_LIST },
40 { DOM_NODE_TAG_REFRESH, REFRESH_STYLE_LIST },
41 { DOM_NODE_TAG_IMAGE, IMAGE_STYLE_LIST },
42 { DOM_NODE_TAG_SPAN, SPAN_STYLE_LIST },
43 { DOM_NODE_TAG_VIDEO, VIDEO_STYLE_LIST },
44 { DOM_NODE_TAG_RATING, RATING_STYLE_LIST },
45 { DOM_NODE_TAG_MARQUEE, MARQUEE_STYLE_LIST },
46 { DOM_NODE_TAG_TEXTAREA, TEXTAREA_STYLE_LIST },
47 { DOM_NODE_TAG_POPUP, POPUP_STYLE_LIST },
48 { DOM_NODE_TAG_LIST, LIST_STYLE_LIST },
49 { DOM_NODE_TAG_INPUT, INPUT_STYLE_LIST },
50 { DOM_NODE_TAG_LABEL, TEXT_STYLE_LIST },
51 { DOM_NODE_TAG_DIVIDER, DIVIDER_STYLE_LIST },
52 { DOM_NODE_TAG_SWITCH, SWITCH_STYLE_LIST },
53 { DOM_NODE_TAG_BUTTON, BUTTON_STYLE_LIST },
54 { DOM_NODE_TAG_SEARCH, SEARCH_STYLE_LIST },
55 };
56
57 const std::map<std::string, std::vector<std::string>> DOMATTRLIST = {
58 { DOM_NODE_TAG_PROGRESS, PROGRESS_ATTR_LIST },
59 { DOM_NODE_TAG_SLIDER, SLIDER_ATTR_LIST },
60 { DOM_NODE_TAG_SWIPER, SWIPER_ATTR_LIST },
61 { DOM_NODE_TAG_SWITCH, SWITCH_ATTR_LIST },
62 { DOM_NODE_TAG_TEXT, TEXT_ATTR_LIST },
63 { DOM_NODE_TAG_SVG_TEXT, SVG_TEXT_ATTR_LIST },
64 { DOM_NODE_TAG_TEXT_PATH, SVG_TEXT_PATH_ATTR_LIST },
65 { DOM_NODE_TAG_TSPAN, SVG_TSPAN_ATTR_LIST },
66 { DOM_NODE_TAG_IMAGE, IMAGE_ATTR_LIST },
67 { DOM_NODE_TAG_SPAN, SPAN_ATTR_LIST },
68 { DOM_NODE_TAG_TABS, TABS_ATTR_LIST },
69 { DOM_NODE_TAG_TAB_BAR, TABBAR_ATTR_LIST },
70 { DOM_NODE_TAG_TAB_CONTENT, TABCONTENT_ATTR_LIST },
71 { DOM_NODE_TAG_REFRESH, REFRESH_ATTR_LIST },
72 { DOM_NODE_TAG_VIDEO, VIDEO_ATTR_LIST },
73 { DOM_NODE_TAG_RATING, RATING_ATTR_LIST },
74 { DOM_NODE_TAG_MARQUEE, MARQUEE_ATTR_LIST },
75 { DOM_NODE_TAG_TEXTAREA, TEXTAREA_ATTR_LIST },
76 { DOM_NODE_TAG_POPUP, POPUP_ATTR_LIST },
77 { DOM_NODE_TAG_LIST, LIST_ATTR_LIST },
78 { DOM_NODE_TAG_INPUT, INPUT_ATTR_LIST },
79 { DOM_NODE_TAG_LABEL, LABEL_ATTR_LIST },
80 { DOM_NODE_TAG_BUTTON, BUTTON_ATTR_LIST },
81 { DOM_NODE_TAG_DIVIDER, DIVIDER_ATTR_LIST },
82 { DOM_NODE_TAG_SEARCH, SEARCH_ATTR_LIST },
83 { DOM_NODE_TAG_IMAGE_ANIMATOR, IMAGE_ANIMATOR_ATTR_LIST },
84 { DOM_NODE_TAG_PIECE, PIECE_ATTR_LIST },
85 { DOM_NODE_TAG_DIV, DIV_ATTR_LIST },
86 { DOM_NODE_TAG_SVG, SVG_ATTR_LIST },
87 { DOM_NODE_TAG_RECT, SVG_RECT_ATTR_LIST },
88 { DOM_NODE_TAG_CIRCLE, SVG_CIRCLE_ATTR_LIST },
89 { DOM_NODE_TAG_ELLIPSE, SVG_ELLIPSE_ATTR_LIST },
90 { DOM_NODE_TAG_PATH, SVG_PATH_ATTR_LIST },
91 { DOM_NODE_TAG_LINE, SVG_LINE_ATTR_LIST },
92 { DOM_NODE_TAG_POLYLINE, SVG_POLYLINE_ATTR_LIST },
93 { DOM_NODE_TAG_POLYGON, SVG_POLYGON_ATTR_LIST },
94 { DOM_NODE_TAG_ANIMATE, SVG_ANIMATE_ATTR_LIST },
95 { DOM_NODE_TAG_ANIMATE_MOTION, SVG_ANIMATE_MOTION_ATTR_LIST },
96 };
97 const std::map<std::string, std::vector<std::string>> DOMEVENTLIST = {
98 { DOM_NODE_TAG_SWIPER, SWIPER_EVENT_LIST },
99 { DOM_NODE_TAG_SLIDER, SLIDER_EVENT_LIST },
100 { DOM_NODE_TAG_SWITCH, SWITCH_EVENT_LIST },
101 { DOM_NODE_TAG_IMAGE, IMAGE_EVENT_LIST },
102 { DOM_NODE_TAG_VIDEO, VIDEO_EVENT_LIST },
103 { DOM_NODE_TAG_REFRESH, REFRESH_EVENT_LIST },
104 { DOM_NODE_TAG_RATING, RATING_EVENT_LIST },
105 { DOM_NODE_TAG_MARQUEE, MARQUEE_EVENT_LIST },
106 { DOM_NODE_TAG_TEXTAREA, TEXTAREA_EVENT_LIST },
107 { DOM_NODE_TAG_POPUP, POPUP_EVENT_LIST },
108 { DOM_NODE_TAG_INPUT, INPUT_EVENT_LIST },
109 { DOM_NODE_TAG_SEARCH, SEARCH_EVENT_LIST },
110 { DOM_NODE_TAG_PIECE, PIECE_EVENT_LIST },
111 };
112
ParseJsonString(const std::string & jsonValue)113 std::unique_ptr<JsonValue> ParseJsonString(const std::string& jsonValue)
114 {
115 return JsonUtil::ParseJsonString(jsonValue);
116 }
117
CreateDomNode(const JsonValue & componentValue,int32_t nodeId)118 RefPtr<DOMNode> CreateDomNode(const JsonValue& componentValue, int32_t nodeId)
119 {
120 if (!componentValue.Contains(DOM_TAG)) {
121 LOGE("not have tag field.");
122 return nullptr;
123 }
124
125 auto typeValue = componentValue.GetValue(DOM_TAG);
126 std::string type = typeValue->GetString();
127 return DOMNodeFactory::GetInstance().GetDocument()->CreateNodeWithId(type, nodeId);
128 }
129
AppendChildNode(const JsonValue & jsonValue,const RefPtr<DOMNode> & parentNode)130 void AppendChildNode(const JsonValue& jsonValue, const RefPtr<DOMNode>& parentNode)
131 {
132 NodeId nodeId = parentNode->GetNodeId() + 1;
133 if (!jsonValue.IsArray()) {
134 auto child = CreateDomNode(jsonValue, nodeId);
135 parentNode->AddNode(child);
136 return;
137 }
138
139 int32_t arraySize = jsonValue.GetArraySize();
140 for (int32_t index = 0; index < arraySize; ++index, nodeId++) {
141 auto item = jsonValue.GetArrayItem(index);
142 auto child = CreateDomNode(*item, nodeId);
143 parentNode->AddNode(child);
144 if (jsonValue.Contains(CHILD_TAG)) {
145 const auto childValue = jsonValue.GetValue(CHILD_TAG);
146 if (childValue != nullptr) {
147 AppendChildNode(*childValue, child);
148 }
149 }
150 }
151 }
152
SetStyleFromJson(const std::string & jsonStr,const RefPtr<DOMNode> & domNode,const RefPtr<Declaration> & declaration)153 void SetStyleFromJson(
154 const std::string& jsonStr, const RefPtr<DOMNode>& domNode, const RefPtr<Declaration>& declaration)
155 {
156 if (!declaration || !domNode) {
157 return;
158 }
159 auto domJson = ParseJsonString(jsonStr);
160 std::vector<std::pair<std::string, std::string>> styles;
161 if (domJson->Contains(COMMON_STYLE)) {
162 const auto commonStyleValue = domJson->GetValue(COMMON_STYLE);
163 int32_t size = commonStyleValue->GetArraySize();
164 for (int32_t index = 0; index < size; index++) {
165 auto item = commonStyleValue->GetArrayItem(index);
166 for (const auto& commonStyle : COMMON_STYLE_LIST) {
167 if (item->Contains(commonStyle)) {
168 styles.emplace_back(commonStyle, item->GetValue(commonStyle)->GetString());
169 break;
170 }
171 }
172 }
173 }
174 std::string type = domJson->GetValue(DOM_TAG)->GetString();
175 if (DOMSTYLELIST.find(type) == DOMSTYLELIST.end()) {
176 LOGD("json file not define style for %s", type.c_str());
177 } else {
178 const std::vector<std::string> styleList = DOMSTYLELIST.find(type)->second;
179 if (domJson->Contains(DOM_STYLE)) {
180 const auto styleValue = domJson->GetValue(DOM_STYLE);
181 int32_t size = styleValue->GetArraySize();
182 for (int32_t index = 0; index < size; index++) {
183 auto item = styleValue->GetArrayItem(index);
184 for (const auto& style : styleList) {
185 if (item->Contains(style)) {
186 styles.emplace_back(style, item->GetValue(style)->GetString());
187 break;
188 }
189 }
190 }
191 }
192 }
193 declaration->SetStyle(styles);
194 domNode->SetStyle(styles);
195 }
196
SetAttrFromJson(const std::string & jsonStr,const RefPtr<DOMNode> & domNode,const RefPtr<Declaration> & declaration)197 void SetAttrFromJson(const std::string& jsonStr, const RefPtr<DOMNode>& domNode, const RefPtr<Declaration>& declaration)
198 {
199 if (!declaration || !domNode) {
200 return;
201 }
202 auto domJson = ParseJsonString(jsonStr);
203 std::string type = domJson->GetValue(DOM_TAG)->GetString();
204 if (DOMATTRLIST.find(type) == DOMATTRLIST.end()) {
205 LOGD("json file not define attribute for %s", type.c_str());
206 return;
207 }
208 const std::vector<std::string> attrList = DOMATTRLIST.find(type)->second;
209 std::vector<std::pair<std::string, std::string>> attrs;
210 if (domJson->Contains(DOM_ATTR)) {
211 const auto attrValue = domJson->GetValue(DOM_ATTR);
212 int32_t size = attrValue->GetArraySize();
213 for (int32_t index = 0; index < size; index++) {
214 auto item = attrValue->GetArrayItem(index);
215 for (const auto& attr : attrList) {
216 if (item->Contains(attr)) {
217 attrs.emplace_back(attr, item->GetValue(attr)->GetString());
218 break;
219 }
220 }
221 }
222 }
223 declaration->SetAttr(attrs);
224 domNode->SetAttr(attrs);
225 }
226
SetEventFromJson(const std::string & jsonStr,const RefPtr<DOMNode> & domNode,const RefPtr<Declaration> & declaration)227 void SetEventFromJson(
228 const std::string& jsonStr, const RefPtr<DOMNode>& domNode, const RefPtr<Declaration>& declaration)
229 {
230 if (!declaration || !domNode) {
231 return;
232 }
233 auto domJson = ParseJsonString(jsonStr);
234 std::vector<std::string> events;
235 if (domJson->Contains(COMMON_EVENT)) {
236 const auto commonEventValue = domJson->GetValue(COMMON_EVENT);
237 int32_t size = commonEventValue->GetArraySize();
238 for (int32_t index = 0; index < size; index++) {
239 auto itemStr = commonEventValue->GetArrayItem(index)->GetString();
240 auto eventIter = std::find_if(std::begin(COMMON_EVENT_LIST), std::end(COMMON_EVENT_LIST),
241 [itemStr](const std::string& commonEvent) { return itemStr == commonEvent; });
242 if (eventIter != std::end(COMMON_EVENT_LIST)) {
243 events.emplace_back(*eventIter);
244 }
245 }
246 }
247 std::string type = domJson->GetValue(DOM_TAG)->GetString();
248 if (DOMEVENTLIST.find(type) == DOMEVENTLIST.end()) {
249 LOGD("json file not define event for %s", type.c_str());
250 } else {
251 const std::vector<std::string> eventList = DOMEVENTLIST.find(type)->second;
252 if (domJson->Contains(DOM_EVENT)) {
253 const auto eventValue = domJson->GetValue(DOM_EVENT);
254 int32_t size = eventValue->GetArraySize();
255 for (int32_t index = 0; index < size; index++) {
256 auto item = eventValue->GetArrayItem(index);
257 if (!item->IsString()) {
258 continue;
259 }
260
261 auto itemStr = item->GetString();
262 auto eventIter = std::find_if(std::begin(eventList), std::end(eventList),
263 [itemStr](const std::string& event) { return itemStr == event; });
264 if (eventIter != std::end(COMMON_EVENT_LIST)) {
265 events.emplace_back(*eventIter);
266 }
267 }
268 }
269 }
270 declaration->AddEvent(PAGE_ID, domNode->GetNodeIdForEvent(), events);
271 domNode->AddEvent(PAGE_ID, events);
272 }
273
274 } // namespace
275
276 DOMNodeFactory::DOMNodeFactory() = default;
277 DOMNodeFactory::~DOMNodeFactory() = default;
278
CreateDOMNodeFromDsl(const std::string & jsonStr)279 RefPtr<DOMNode> DOMNodeFactory::CreateDOMNodeFromDsl(const std::string& jsonStr)
280 {
281 auto domJson = ParseJsonString(jsonStr);
282 auto typeValue = domJson->GetValue(DOM_TAG);
283 std::string type = typeValue->GetString();
284 document_ = AceType::MakeRefPtr<DOMDocument>(DOM_ROOT_NODE_ID_BASE);
285 RefPtr<DOMNode> domNodeRoot = document_->CreateNodeWithId(type, DOM_ROOT_NODE_ID_BASE);
286
287 if (!context_) {
288 auto frontend = AceType::MakeRefPtr<MockFrontend>();
289 auto platformWindow = std::make_unique<MockPlatformWindow>();
290 auto window = std::make_unique<Window>(std::move(platformWindow));
291 context_ = AceType::MakeRefPtr<PipelineContext>(std::move(window), nullptr, nullptr, nullptr, frontend, 0);
292 context_->SetThemeManager(AceType::MakeRefPtr<ThemeManagerImpl>());
293 }
294
295 domNodeRoot->SetPipelineContext(context_);
296 domNodeRoot->InitializeStyle();
297 auto declaration = domNodeRoot->GetDeclaration();
298 if (declaration) {
299 declaration->BindPipelineContext(context_);
300 declaration->InitializeStyle();
301 }
302 SetAttrFromJson(jsonStr, domNodeRoot, declaration);
303 SetStyleFromJson(jsonStr, domNodeRoot, declaration);
304 SetEventFromJson(jsonStr, domNodeRoot, declaration);
305 domNodeRoot->GenerateComponentNode();
306
307 if (domJson->Contains(CHILD_TAG)) {
308 const auto childValue = domJson->GetValue(CHILD_TAG);
309 if (childValue != nullptr) {
310 AppendChildNode(*childValue, domNodeRoot);
311 }
312 }
313 return domNodeRoot;
314 }
315
GetBoxChildComponent(const RefPtr<DOMNode> & domNode)316 RefPtr<BoxComponent> DOMNodeFactory::GetBoxChildComponent(const RefPtr<DOMNode>& domNode)
317 {
318 RefPtr<BoxComponent> boxComponent = domNode->GetBoxComponent();
319 return boxComponent;
320 }
321
322 } // namespace OHOS::Ace::Framework
323