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