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