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 "directive/descriptor_utils.h"
17 #include "ace_log.h"
18 #include "directive/directive_watcher_callback.h"
19 #include "wrapper/js.h"
20
21 namespace OHOS {
22 namespace ACELite {
23 const char * const DescriptorUtils::DESCRIPTOR_ATTR_GETTER = "getter";
24 const char * const DescriptorUtils::DESCRIPTOR_ATTR_RENDER = "render";
25 const char * const DescriptorUtils::DESCRIPTOR_ATTR_IF = "if";
26 const char * const DescriptorUtils::DESCRIPTOR_ATTR_FOR = "for";
27 const char * const DescriptorUtils::DESCRIPTOR_ATTR_RENDERED = "rendered";
28 const char * const DescriptorUtils::WATCHER_OPTION_ELEMENT = "element";
29 const char * const DescriptorUtils::WATCHER_OPTION_DESCRIPTOR = "descriptor";
30
CreateIfDescriptor(JSValue getter,JSValue render)31 JSValue DescriptorUtils::CreateIfDescriptor(JSValue getter, JSValue render)
32 {
33 return CreateDescriptor(DESCRIPTOR_ATTR_IF, getter, render);
34 }
35
CreateForDescriptor(JSValue getter,JSValue render)36 JSValue DescriptorUtils::CreateForDescriptor(JSValue getter, JSValue render)
37 {
38 return CreateDescriptor(DESCRIPTOR_ATTR_FOR, getter, render);
39 }
40
CreateDescriptorWatcher(JSValue element,JSValue descriptor)41 JSValue DescriptorUtils::CreateDescriptorWatcher(JSValue element, JSValue descriptor)
42 {
43 JSValue getter = JSObject::Get(descriptor, DESCRIPTOR_ATTR_GETTER);
44 JSValue options = JSObject::Create();
45 // We should change the children of element when watcher callaback is triggered.
46 JSObject::Set(options, WATCHER_OPTION_ELEMENT, element);
47 // We should know which descriptor condition is changed.
48 JSObject::Set(options, WATCHER_OPTION_DESCRIPTOR, descriptor);
49
50 JSValue watcher = CreateWatcher(getter, DirectiveWatcherCallback::Handler, options);
51 JSRelease(options);
52 JSRelease(getter);
53
54 return watcher;
55 }
56
IsIfDescriptor(JSValue descriptor)57 bool DescriptorUtils::IsIfDescriptor(JSValue descriptor)
58 {
59 return IsDescriptor(DESCRIPTOR_ATTR_IF, descriptor);
60 }
61
IsForDescriptor(JSValue descriptor)62 bool DescriptorUtils::IsForDescriptor(JSValue descriptor)
63 {
64 return IsDescriptor(DESCRIPTOR_ATTR_FOR, descriptor);
65 }
66
IsIfDescriptorShown(JSValue descriptor)67 bool DescriptorUtils::IsIfDescriptorShown(JSValue descriptor)
68 {
69 JSValue getter = JSObject::Get(descriptor, DESCRIPTOR_ATTR_GETTER);
70 JSValue condition = CallWithRootAbilitySlice(getter);
71 bool isShown = JSBoolean::Value(condition);
72 JSRelease(condition);
73 JSRelease(getter);
74 return isShown;
75 }
76
RenderIfDescriptor(JSValue descriptor)77 JSValue DescriptorUtils::RenderIfDescriptor(JSValue descriptor)
78 {
79 JSValue render = JSObject::Get(descriptor, DESCRIPTOR_ATTR_RENDER);
80 JSValue rendered = CallWithRootAbilitySlice(render);
81 JSRelease(render);
82 JSObject::Set(descriptor, DESCRIPTOR_ATTR_RENDERED, rendered);
83 return rendered;
84 }
85
RenderForDescriptor(JSValue descriptor)86 JSValue DescriptorUtils::RenderForDescriptor(JSValue descriptor)
87 {
88 JSValue getter = JSObject::Get(descriptor, DESCRIPTOR_ATTR_GETTER);
89
90 JSValue array = CallWithRootAbilitySlice(getter);
91 JSRelease(getter);
92
93 if (JSUndefined::Is(array)) {
94 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to RenderForDescriptor because the result value is undefined.");
95 return JSUndefined::Create();
96 }
97
98 JSValue render = JSObject::Get(descriptor, DESCRIPTOR_ATTR_RENDER);
99 // execute `array.map(render)`.
100 JSValue rendered = JSArray::Map(array, render);
101 JSRelease(render);
102 JSRelease(array);
103 JSObject::Set(descriptor, DESCRIPTOR_ATTR_RENDERED, rendered);
104 return rendered;
105 }
106
GetDescriptorRendered(JSValue descriptor)107 JSValue DescriptorUtils::GetDescriptorRendered(JSValue descriptor)
108 {
109 return JSObject::Get(descriptor, DESCRIPTOR_ATTR_RENDERED);
110 }
111
DelIfDescriptorRendered(JSValue descriptor)112 void DescriptorUtils::DelIfDescriptorRendered(JSValue descriptor)
113 {
114 JSValue descriptorOrElement = GetDescriptorRendered(descriptor);
115 if (!JSUndefined::Is(descriptorOrElement)) {
116 JSObject::Del(descriptor, DESCRIPTOR_ATTR_RENDERED);
117 // the rendered property need to be released
118 // and ReleaseDescriptorOrElement function will release it.
119 ReleaseDescriptorOrElement(descriptorOrElement);
120 }
121 // decrease the count of reference increased by jerry_get_property
122 JSRelease(descriptorOrElement);
123 }
124
DelForDescriptorRendered(JSValue descriptor)125 void DescriptorUtils::DelForDescriptorRendered(JSValue descriptor)
126 {
127 JSValue descriptorOrElements = GetDescriptorRendered(descriptor);
128 if (!JSUndefined::Is(descriptorOrElements)) {
129 JSObject::Del(descriptor, DESCRIPTOR_ATTR_RENDERED);
130 ReleaseDescriptorOrElements(descriptorOrElements);
131 // the rendered property need to be released
132 // but ReleaseDescriptorOrElements function only release its element.
133 JSRelease(descriptorOrElements);
134 }
135 // decrease the count of reference increased by jerry_get_property
136 JSRelease(descriptorOrElements);
137 }
138
ReleaseDescriptorOrElements(JSValue descriptorOrElements)139 void DescriptorUtils::ReleaseDescriptorOrElements(JSValue descriptorOrElements)
140 {
141 uint16_t size = JSArray::Length(descriptorOrElements);
142 for (uint16_t idx = 0; idx < size; ++idx) {
143 JSValue descriptorOrElement = JSArray::Get(descriptorOrElements, idx);
144 // Don't release descriptorOrElement after ReleaseDescriptorOrElement function
145 // because ReleaseDescriptorOrElement will release descriptorOrElement
146 ReleaseDescriptorOrElement(descriptorOrElement);
147 }
148 }
149
ReleaseDescriptorOrElement(JSValue descriptorOrElement)150 void DescriptorUtils::ReleaseDescriptorOrElement(JSValue descriptorOrElement)
151 {
152 if (IsForDescriptor(descriptorOrElement)) {
153 ReleaseForDescriptor(descriptorOrElement);
154 } else if (IsIfDescriptor(descriptorOrElement)) {
155 ReleaseIfDescriptor(descriptorOrElement);
156 } else {
157 ReleaseElement(descriptorOrElement);
158 }
159 }
160
ReleaseForDescriptor(JSValue descriptor)161 void DescriptorUtils::ReleaseForDescriptor(JSValue descriptor)
162 {
163 if (JSUndefined::Is(descriptor)) {
164 return;
165 }
166 DelForDescriptorRendered(descriptor);
167 JSRelease(descriptor);
168 }
169
ReleaseIfDescriptor(JSValue descriptor)170 void DescriptorUtils::ReleaseIfDescriptor(JSValue descriptor)
171 {
172 if (JSUndefined::Is(descriptor)) {
173 return;
174 }
175 DelIfDescriptorRendered(descriptor);
176 JSRelease(descriptor);
177 }
178
ReleaseElement(JSValue element)179 void DescriptorUtils::ReleaseElement(JSValue element)
180 {
181 if (JSUndefined::Is(element)) {
182 return;
183 }
184
185 Component *component = nullptr;
186 bool isBinded = JSObject::GetNativePointer(element, reinterpret_cast<void **>(&component));
187 if (!isBinded || (component == nullptr)) {
188 return;
189 }
190
191 bool isSuccess = JSObject::DelNativePointer(element);
192 if (!isSuccess) {
193 HILOG_WARN(HILOG_MODULE_ACE, "delete native view pointer from native element failed.");
194 }
195
196 if (component->GetComponentName() != K_LIST) {
197 JSValue descriptors = component->GetDescriptors();
198 if (!JSUndefined::Is(descriptors)) {
199 ReleaseDescriptorOrElements(descriptors);
200 }
201 }
202
203 component->Release();
204 delete component;
205 component = nullptr;
206 }
207
CreateDescriptor(const char * const type,JSValue getter,JSValue render)208 JSValue DescriptorUtils::CreateDescriptor(const char * const type, JSValue getter, JSValue render)
209 {
210 if ((type == nullptr) || (strlen(type) == 0)) {
211 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create descriptor because the type argument is null or empty.");
212 return UNDEFINED;
213 }
214
215 if (!JSFunction::Is(getter)) {
216 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create descriptor because the getter argument is not a function.");
217 return UNDEFINED;
218 }
219
220 if (!JSFunction::Is(render)) {
221 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to create descriptor because the render argument is not a function.");
222 return UNDEFINED;
223 }
224
225 JSValue descriptor = JSObject::Create();
226 JSValue value = JSBoolean::Create(true);
227 JSObject::Set(descriptor, type, value);
228 JSRelease(value);
229
230 JSObject::Set(descriptor, DESCRIPTOR_ATTR_GETTER, getter);
231 JSObject::Set(descriptor, DESCRIPTOR_ATTR_RENDER, render);
232
233 return descriptor;
234 }
235
IsDescriptor(const char * const type,JSValue descriptor)236 bool DescriptorUtils::IsDescriptor(const char * const type, JSValue descriptor)
237 {
238 if (JSUndefined::Is(descriptor)) {
239 return false;
240 }
241
242 JSValue value = JSObject::Get(descriptor, type);
243 bool result = JSBoolean::Value(value);
244 JSRelease(value);
245 return result;
246 }
247 } // namespace ACELite
248 } // namespace OHOS
249