1 /*
2 * Copyright (c) 2020-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 "stylemgr/app_style.h"
17 #include "ace_log.h"
18 #include "securec.h"
19
20 namespace OHOS {
21 namespace ACELite {
SetStyleName(const char * const name,size_t nameLen)22 void AppStyle::SetStyleName(const char * const name, size_t nameLen)
23 {
24 if ((nameLen <= 0) || (nameLen >= NAME_LENGTH_MAX) || (name == nullptr) || (strlen(name) == 0)) {
25 return;
26 }
27 styleName_ = static_cast<char *>(ace_malloc(sizeof(char) * (nameLen + 1)));
28 if (styleName_ == nullptr) {
29 HILOG_ERROR(HILOG_MODULE_ACE, "create style_name failed.");
30 return;
31 }
32 if (memcpy_s(styleName_, nameLen, name, nameLen) != EOK) {
33 HILOG_ERROR(HILOG_MODULE_ACE, "style_name set string value error");
34 ace_free(styleName_);
35 styleName_ = nullptr;
36 return;
37 }
38 *(styleName_ + nameLen) = '\0';
39 }
40
Reset()41 void AppStyle::Reset()
42 {
43 const AppStyleItem *next = nullptr;
44 while (firstStyleItem_ != nullptr) {
45 next = firstStyleItem_->GetNext();
46 delete firstStyleItem_;
47 firstStyleItem_ = next;
48 }
49 lastStyleItem_ = nullptr;
50 if (styleName_ != nullptr) {
51 ace_free(styleName_);
52 styleName_ = nullptr;
53 }
54 }
55
AddStyleItem(AppStyleItem * newStyleItem)56 void AppStyle::AddStyleItem(AppStyleItem *newStyleItem)
57 {
58 if (newStyleItem == nullptr) {
59 return;
60 }
61
62 if (firstStyleItem_ == nullptr) {
63 firstStyleItem_ = newStyleItem;
64 lastStyleItem_ = newStyleItem;
65 } else {
66 newStyleItem->SetPre(lastStyleItem_);
67 lastStyleItem_->SetNext(newStyleItem);
68 lastStyleItem_ = newStyleItem;
69 }
70 }
71
GetStyleItemByName(const char * const stylePropName) const72 const AppStyleItem *AppStyle::GetStyleItemByName(const char * const stylePropName) const
73 {
74 if (stylePropName == nullptr) {
75 return nullptr;
76 }
77 size_t len = strlen(stylePropName);
78 uint16_t keyId = KeyParser::ParseKeyId(stylePropName, len);
79 return GetStyleItemByNameId(keyId);
80 }
81
GetStyleItemByNameId(uint16_t stylePropNameId) const82 const AppStyleItem *AppStyle::GetStyleItemByNameId(uint16_t stylePropNameId) const
83 {
84 if (!KeyParser::IsKeyValid(stylePropNameId)) {
85 return nullptr;
86 }
87
88 const AppStyleItem *styleItem = firstStyleItem_;
89 while (styleItem != nullptr) {
90 if (styleItem->GetPropNameId() == stylePropNameId) {
91 return styleItem;
92 }
93
94 styleItem = styleItem->GetNext();
95 }
96 return nullptr;
97 }
98
AddItemsInLoop(jerry_value_t object,AppStyle & newStyle)99 void AppStyle::AddItemsInLoop(jerry_value_t object, AppStyle &newStyle)
100 {
101 jerry_value_t propKeys = jerry_get_object_keys(object);
102 uint16_t propKeySize = jerry_get_array_length(propKeys);
103 for (uint16_t index = 0; index < propKeySize; index++) {
104 // convert prop key into char
105 jerry_value_t propKey = jerry_get_property_by_index(propKeys, index);
106 jerry_value_t propValue = jerry_get_property(object, propKey);
107 AppStyleItem *newStyleItem = AppStyleItem::GenerateFromJSValue(propKey, propValue);
108 newStyle.AddStyleItem(newStyleItem);
109 ReleaseJerryValue(propKey, propValue, VA_ARG_END_FLAG);
110 }
111 jerry_release_value(propKeys);
112 }
113
AddKeyFramesItemsInLoop(jerry_value_t objFrom,jerry_value_t objTo,AppStyle & newStyle)114 void AppStyle::AddKeyFramesItemsInLoop(jerry_value_t objFrom, jerry_value_t objTo, AppStyle &newStyle)
115 {
116 if (jerry_value_is_null(objFrom) || jerry_value_is_null(objTo)) {
117 return;
118 }
119 jerry_value_t propKeysFrom = jerry_get_object_keys(objFrom);
120 uint16_t propKeySizeFrom = jerry_get_array_length(propKeysFrom);
121
122 jerry_value_t propKeyFrom;
123 jerry_value_t propValueFrom;
124 jerry_value_t propValueTo;
125 jerry_value_t propValue = UNDEFINED;
126
127 char *keyFrom = nullptr;
128 AppStyleItem *newStyleItem = nullptr;
129 for (uint16_t i = 0; i < propKeySizeFrom; i++) {
130 bool isItemNeedToAdd = false;
131 propKeyFrom = jerry_get_property_by_index(propKeysFrom, i); // transform, height, background-color
132 propValueFrom = jerry_get_property(objFrom, propKeyFrom); // {\"translateX\":\"50px\"}, -5px, #f76160
133 propValueTo = jerry_get_property(objTo, propKeyFrom);
134
135 if (JerryHasProperty(objTo, propKeyFrom)) { // key exist in to object
136 keyFrom = MallocStringOf(propKeyFrom);
137 const char * const transitionTransform = "transform";
138 if ((keyFrom != nullptr) &&
139 !strcmp(keyFrom, transitionTransform)) { // transform type, include "translateX, translateY, rotate"
140 propValue = AddKeyFramesTransformValue(propValueFrom, propValueTo, isItemNeedToAdd, propKeyFrom);
141 } else {
142 isItemNeedToAdd = true;
143 propValue = ConcatJerryString(propValueFrom, propValueTo);
144 }
145 if (keyFrom != nullptr) {
146 ace_free(keyFrom);
147 keyFrom = nullptr;
148 }
149 }
150
151 if (isItemNeedToAdd) {
152 newStyleItem = AppStyleItem::GenerateFromJSValue(propKeyFrom, propValue);
153 newStyle.AddStyleItem(newStyleItem);
154 jerry_release_value(propValue);
155 }
156 ReleaseJerryValue(propKeyFrom, propValueFrom, propValueTo, VA_ARG_END_FLAG);
157 }
158
159 jerry_release_value(propKeysFrom);
160 }
161
AddKeyFramesTransformValue(jerry_value_t propValueFrom,jerry_value_t propValueTo,bool & isItemNeedToAdd,jerry_value_t & propKeyFrom)162 jerry_value_t AppStyle::AddKeyFramesTransformValue(jerry_value_t propValueFrom,
163 jerry_value_t propValueTo,
164 bool &isItemNeedToAdd,
165 jerry_value_t &propKeyFrom)
166 {
167 jerry_value_t propValue = UNDEFINED;
168 if (jerry_value_is_undefined(propValueFrom) || jerry_value_is_undefined(propValueTo)) {
169 HILOG_ERROR(HILOG_MODULE_ACE, "transform prop value must be set.");
170 return propValue;
171 }
172 jerry_value_t transformKeysFrom = jerry_get_object_keys(propValueFrom);
173 jerry_value_t transformKeysTo = jerry_get_object_keys(propValueTo);
174 if ((!jerry_value_is_undefined(transformKeysFrom)) && (!jerry_value_is_undefined(transformKeysTo))) {
175 int8_t valueIndex = 0;
176 jerry_value_t transformKeyFrom = jerry_get_property_by_index(transformKeysFrom, valueIndex);
177 jerry_value_t transformKeyTo = jerry_get_property_by_index(transformKeysTo, valueIndex);
178 if (transformKeyFrom == transformKeyTo) {
179 jerry_value_t transformValueFrom = jerry_get_property(propValueFrom, transformKeyFrom);
180 jerry_value_t transformValueTo = jerry_get_property(propValueTo, transformKeyTo);
181 if ((!jerry_value_is_undefined(transformValueFrom)) && (!jerry_value_is_undefined(transformValueTo))) {
182 jerry_release_value(propKeyFrom);
183 propKeyFrom = jerry_acquire_value(transformKeyFrom);
184 isItemNeedToAdd = true;
185 propValue = ConcatJerryString(transformValueFrom, transformValueTo);
186 } else {
187 HILOG_ERROR(HILOG_MODULE_ACE, "None style to parse.");
188 }
189 ReleaseJerryValue(transformValueFrom, transformValueTo, VA_ARG_END_FLAG);
190 }
191 ReleaseJerryValue(transformKeyFrom, transformKeyTo, VA_ARG_END_FLAG);
192 } else {
193 HILOG_ERROR(HILOG_MODULE_ACE, "None style to parse.");
194 }
195 ReleaseJerryValue(transformKeysFrom, transformKeysTo, VA_ARG_END_FLAG);
196
197 return propValue;
198 }
199
MergeAnimationString(char * dest,uint16_t destSz,const char * const src1,const char * const src2)200 bool AppStyle::MergeAnimationString(char *dest, uint16_t destSz, const char * const src1, const char * const src2)
201 {
202 if (strcat_s(dest, destSz, src1) != 0) {
203 return false;
204 }
205 if (strcat_s(dest, destSz, ANIMATION_VALUE_SEP) != 0) {
206 return false;
207 }
208 if (strcat_s(dest, destSz, src2) != 0) {
209 return false;
210 }
211 dest[destSz - 1] = '\0';
212 return true;
213 }
214
ConcatJerryString(jerry_value_t strA,jerry_value_t strB)215 jerry_value_t AppStyle::ConcatJerryString(jerry_value_t strA, jerry_value_t strB)
216 {
217 char *stringA = MallocStringOf(strA);
218 if (stringA == nullptr) {
219 return jerry_create_null();
220 }
221 char *stringB = MallocStringOf(strB);
222 if (stringB == nullptr) {
223 ace_free(stringA);
224 stringA = nullptr;
225 return jerry_create_null();
226 }
227 const char * const pixelUnit = "px";
228 char *next = nullptr;
229 char *strtokA = stringA;
230 char *strtokB = stringB;
231 if (strstr(stringA, pixelUnit)) {
232 strtokA = strtok_s(stringA, pixelUnit, &next);
233 next = nullptr;
234 }
235 if (strstr(stringB, pixelUnit)) {
236 strtokB = strtok_s(stringB, pixelUnit, &next);
237 }
238 if ((strtokA == nullptr) || (strtokB == nullptr)) {
239 ace_free(stringA);
240 stringA = nullptr;
241 ace_free(stringB);
242 stringB = nullptr;
243 return jerry_create_null();
244 }
245 size_t strtokALen = strlen(strtokA);
246 size_t strtokBLen = strlen(strtokB);
247 if ((strtokALen == 0) || (strtokALen >= (UINT16_MAX - 1)) || (strtokBLen == 0) ||
248 (strtokBLen >= (UINT16_MAX - 1))) {
249 ace_free(stringA);
250 stringA = nullptr;
251 ace_free(stringB);
252 stringB = nullptr;
253 return jerry_create_null();
254 }
255 bool result = true;
256 size_t size = strlen(strtokA) + strlen(strtokB) + strlen(ANIMATION_VALUE_SEP) + 1;
257 const uint16_t maxBytesNum = 1024;
258 if ((size >= maxBytesNum)) { // we only support 1kb
259 result = false;
260 }
261 char *newStr = nullptr;
262 if (result) {
263 newStr = static_cast<char *>(ace_malloc(size));
264 if (newStr == nullptr) {
265 HILOG_ERROR(HILOG_MODULE_ACE, "malloc space error");
266 ace_free(stringA);
267 stringA = nullptr;
268 ace_free(stringB);
269 stringB = nullptr;
270 return jerry_create_null();
271 }
272 newStr[0] = '\0';
273 result = MergeAnimationString(newStr, size, strtokA, strtokB);
274 }
275
276 jerry_value_t propValue;
277 if (result) {
278 propValue = jerry_create_string(reinterpret_cast<jerry_char_t *>(newStr));
279 } else {
280 propValue = jerry_create_null();
281 }
282 ace_free(stringA);
283 stringA = nullptr;
284 ace_free(stringB);
285 stringB = nullptr;
286 ACE_FREE(newStr);
287 return propValue;
288 }
289
GenerateFromJS(jerry_value_t styleKey,jerry_value_t styleValue,bool isKeyFrames)290 AppStyle *AppStyle::GenerateFromJS(jerry_value_t styleKey, jerry_value_t styleValue, bool isKeyFrames)
291 {
292 char *styleNameBuffer = MallocStringOf(styleKey);
293 size_t strLen = 0;
294 if (styleNameBuffer == nullptr) {
295 HILOG_ERROR(HILOG_MODULE_ACE, "convert style name to char failed, will be dropped\n");
296 return nullptr;
297 }
298 strLen = strlen(styleNameBuffer);
299 if (strLen == 0 || (strLen >= UINT16_MAX)) {
300 HILOG_ERROR(HILOG_MODULE_ACE, "style name length is 0 or max, will be dropped\n");
301 ace_free(styleNameBuffer);
302 styleNameBuffer = nullptr;
303 return nullptr;
304 }
305
306 AppStyle *newStyle = new AppStyle();
307 if (newStyle == nullptr) {
308 HILOG_ERROR(HILOG_MODULE_ACE, "create style error");
309 ace_free(styleNameBuffer);
310 styleNameBuffer = nullptr;
311 return nullptr;
312 }
313
314 newStyle->SetStyleName(static_cast<const char *>(styleNameBuffer), strLen); // translateX #aaa
315 ace_free(styleNameBuffer);
316 styleNameBuffer = nullptr;
317
318 if (isKeyFrames) {
319 jerry_value_t fromObj = jerry_get_property_by_index(styleValue, 0);
320 jerry_value_t toObj = jerry_get_property_by_index(styleValue, 1);
321 AddKeyFramesItemsInLoop(fromObj, toObj, *newStyle);
322 ReleaseJerryValue(toObj, fromObj, VA_ARG_END_FLAG);
323 } else {
324 AddItemsInLoop(styleValue, *newStyle);
325 }
326
327 return newStyle;
328 }
329
CombineStyles(AppStyle & dest,const AppStyle & source,bool overwrite)330 void AppStyle::CombineStyles(AppStyle &dest, const AppStyle &source, bool overwrite)
331 {
332 const AppStyleItem *styleItem = source.GetFirst();
333 while (styleItem != nullptr) {
334 const AppStyleItem *currentStyleItemInSource = styleItem;
335 styleItem = styleItem->GetNext();
336 const AppStyleItem *existOneInDest = dest.GetStyleItemByNameId(currentStyleItemInSource->GetPropNameId());
337
338 if (existOneInDest == nullptr) {
339 dest.AddStyleItem(AppStyleItem::CopyFrom(currentStyleItemInSource));
340 continue;
341 }
342
343 if (!overwrite) {
344 // exist one has higher priority
345 continue;
346 }
347
348 // the new one has higher priority, to over wirte exist one
349 const_cast<AppStyleItem *>(existOneInDest)->UpdateValueFrom(*currentStyleItemInSource);
350 }
351 }
352 } // namespace ACELite
353 } // namespace OHOS
354