1 /*
2  * Copyright (c) 2020 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 "presets/render_module.h"
17 #include "ace_log.h"
18 #include "component_factory.h"
19 #include "component_utils.h"
20 #include "directive/descriptor_utils.h"
21 #include "js_app_context.h"
22 #include "js_profiler.h"
23 namespace OHOS {
24 namespace ACELite {
25 const char * const RenderModule::FUNC_CREATE_ELEMENT = "_c";
26 const char * const RenderModule::FUNC_INIT_STYLE_SHEET = "initStyleSheet";
27 const char * const RenderModule::FUNC_LOOP_RENDER = "_l";
28 const char * const RenderModule::FUNC_CONDITIONAL_RENDER = "_i";
29 const int RenderModule::ARG_LENGTH_TAG_ONLY = 1;
30 const int RenderModule::ARG_LENGTH_WITHOUT_OPTIONS = 2;
31 const int RenderModule::ARG_LENGTH_WITH_OPTIONS = 3;
32 const int RenderModule::ARG_LENGTH_RENDER = 2;
33 
Init()34 void RenderModule::Init()
35 {
36     CreateNamedFunction(FUNC_CREATE_ELEMENT, CreateElement);
37     CreateNamedFunction(FUNC_LOOP_RENDER, LoopRender);
38     CreateNamedFunction(FUNC_CONDITIONAL_RENDER, ConditionalRender);
39     CreateNamedFunction(FUNC_INIT_STYLE_SHEET, InitStyleSheet);
40 }
41 
CreateElement(jerry_value_t tagName,jerry_value_t options,jerry_value_t children)42 jerry_value_t RenderModule::CreateElement(jerry_value_t tagName, jerry_value_t options, jerry_value_t children)
43 {
44     uint16_t tagNameLength = 0;
45     char *componentName = MallocStringOf(tagName, &tagNameLength);
46     if (componentName == nullptr) {
47         return UNDEFINED;
48     }
49     if (tagNameLength == 0) {
50         ace_free(componentName);
51         componentName = nullptr;
52         return UNDEFINED;
53     }
54 
55     uint16_t componentNameId = KeyParser::ParseKeyId(componentName, tagNameLength);
56     ace_free(componentName);
57     componentName = nullptr;
58 
59     // create component by tag name using factory
60     Component *component = ComponentFactory::CreateComponent(componentNameId, options, children);
61     if (component == nullptr) {
62         // Release all children before we return UNDEFINED to avoid the children becoming ownerless in this case.
63         HILOG_ERROR(HILOG_MODULE_ACE, "Fail to create element because the tag is not supported.");
64         DescriptorUtils::ReleaseDescriptorOrElements(children);
65         return UNDEFINED;
66     }
67 
68     // component begin to render
69     bool renderResult = component->Render();
70     if (!renderResult) {
71         // render failed, drop this element by release its all children and itself
72         DescriptorUtils::ReleaseDescriptorOrElements(children);
73         component->Release();
74         delete component;
75         component = nullptr;
76         return UNDEFINED;
77     }
78 
79     // render successfully
80     return component->GetNativeElement();
81 }
82 
CreateElement(const jerry_value_t func,const jerry_value_t context,const jerry_value_t * args,const jerry_length_t argsNum)83 jerry_value_t RenderModule::CreateElement(const jerry_value_t func,
84                                           const jerry_value_t context,
85                                           const jerry_value_t *args,
86                                           const jerry_length_t argsNum)
87 {
88     jerry_value_t tagName;
89     jerry_value_t options;
90     jerry_value_t children;
91     if (argsNum == ARG_LENGTH_WITH_OPTIONS) {
92         tagName = args[0];
93         options = args[1];
94         const int8_t childrenNum = 2;
95         children = args[childrenNum];
96     } else if (argsNum == ARG_LENGTH_WITHOUT_OPTIONS) {
97         tagName = args[0];
98         if (jerry_value_is_array(args[1])) {
99             options = UNDEFINED;
100             children = args[1];
101         } else {
102             options = args[1];
103             children = UNDEFINED;
104         }
105     } else if (argsNum == ARG_LENGTH_TAG_ONLY) {
106         tagName = args[0];
107         options = UNDEFINED;
108         children = UNDEFINED;
109     } else {
110         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create element cause by invalid arguments.");
111         return UNDEFINED;
112     }
113 
114     return CreateElement(tagName, options, children);
115 }
116 
InitStyleSheet(const jerry_value_t func,const jerry_value_t context,const jerry_value_t * args,const jerry_length_t argsNum)117 jerry_value_t RenderModule::InitStyleSheet(const jerry_value_t func,
118                                            const jerry_value_t context,
119                                            const jerry_value_t *args,
120                                            const jerry_length_t argsNum)
121 {
122     AppStyleManager *manager = const_cast<AppStyleManager *>(JsAppContext::GetInstance()->GetStyleManager());
123 
124     if (argsNum == 0 || manager == nullptr) {
125         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to initialize style sheet cause by invalid arguments or empty manager!");
126         return jerry_create_boolean(false);
127     }
128     START_TRACING(STYLESHEET_INIT);
129     manager->InitStyleSheet(args[0]);
130     STOP_TRACING();
131     return jerry_create_boolean(true);
132 }
133 
LoopRender(const jerry_value_t func,const jerry_value_t context,const jerry_value_t * args,const jerry_length_t length)134 jerry_value_t RenderModule::LoopRender(const jerry_value_t func,
135                                        const jerry_value_t context,
136                                        const jerry_value_t *args,
137                                        const jerry_length_t length)
138 {
139     if (length != ARG_LENGTH_RENDER) {
140         HILOG_ERROR(HILOG_MODULE_ACE,
141                     "Failed to LoopRender as the length of arguments invalid. Expect 2 but %{public}d", length);
142         return UNDEFINED;
143     }
144 
145     return DescriptorUtils::CreateForDescriptor(args[0], args[1]);
146 }
147 
ConditionalRender(const jerry_value_t func,const jerry_value_t context,const jerry_value_t * args,const jerry_length_t argsNum)148 jerry_value_t RenderModule::ConditionalRender(const jerry_value_t func,
149                                               const jerry_value_t context,
150                                               const jerry_value_t *args,
151                                               const jerry_length_t argsNum)
152 {
153     if (argsNum != ARG_LENGTH_RENDER) {
154         HILOG_ERROR(HILOG_MODULE_ACE, "Failed to ConditionalRender cause by invlaid paramters. Expect 2 but %{public}d",
155                     argsNum);
156         return UNDEFINED;
157     }
158 
159     return DescriptorUtils::CreateIfDescriptor(args[0], args[1]);
160 }
161 } // namespace ACELite
162 } // namespace OHOS
163