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 "stylemgr/app_style_sheet.h"
17 #include "condition_arbitrator.h"
18 #include "js_fwk_common.h"
19 #include "scope_js_value.h"
20 
21 namespace OHOS {
22 namespace ACELite {
Reset()23 void AppStyleSheet::Reset()
24 {
25     if (idSelectors_ != nullptr) {
26         idSelectors_->Reset();
27         delete idSelectors_;
28         idSelectors_ = nullptr;
29     }
30 
31     if (classSelectors_ != nullptr) {
32         classSelectors_->Reset();
33         delete classSelectors_;
34         classSelectors_ = nullptr;
35     }
36 
37     if (keyFrameSelectors_ != nullptr) {
38         keyFrameSelectors_->Reset();
39         delete keyFrameSelectors_;
40         keyFrameSelectors_ = nullptr;
41     }
42 }
43 
InitSheet(jerry_value_t styleSheetObj)44 void AppStyleSheet::InitSheet(jerry_value_t styleSheetObj)
45 {
46     if (jerry_value_is_undefined(styleSheetObj)) {
47         return;
48     }
49 
50     // clear previous style sheet list
51     Reset();
52 
53     // initializa all media query selectors first, as all media query selectors have higher priority
54     InitMediaSelectors(styleSheetObj);
55 
56     // initialize all other normal selectors
57     InitNormalSelectors(styleSheetObj);
58 }
59 
InitMediaSelectors(const jerry_value_t styleSheetObj)60 void AppStyleSheet::InitMediaSelectors(const jerry_value_t styleSheetObj)
61 {
62     // check if media query exists in style sheet
63     const char * const mediaQueryArrayKeyName = "@media";
64     jerry_value_t propNameV =
65             jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(mediaQueryArrayKeyName)));
66     ScopeJSValue propNameP(propNameV);
67     if (!HasOwnProperty(styleSheetObj, propNameV)) {
68         // no media querry items
69         return;
70     }
71 
72     ScopeJSValue mediaQueryArrayValue(jerry_get_property(styleSheetObj, propNameV));
73     if (!jerry_value_is_array(mediaQueryArrayValue.Obain())) {
74         return;
75     }
76 
77     uint32_t conditionCounts = jerry_get_array_length(mediaQueryArrayValue.Obain());
78     const uint32_t maxConditionCount = 256;
79     if (conditionCounts == 0 || conditionCounts > maxConditionCount) {
80         return;
81     }
82     for (uint32_t index = 0; index < conditionCounts; index++) {
83         // get the array item @ index position
84         jerry_value_t mediaArrayItemV = jerry_get_property_by_index(mediaQueryArrayValue.Obain(), index);
85         ScopeJSValue mediaArrayItemP(mediaArrayItemV);
86         // handle single one
87         HandleSingleMediaItem(mediaArrayItemV);
88     }
89 }
90 
HandleSingleMediaItem(const jerry_value_t mediaItem)91 void AppStyleSheet::HandleSingleMediaItem(const jerry_value_t mediaItem)
92 {
93     const char * const conditionKeyName = "condition";
94     jerry_value_t conditionKeyV = jerry_create_string(reinterpret_cast<const jerry_char_t *>(conditionKeyName));
95     ScopeJSValue conditionKeyP(conditionKeyV);
96     if (!JerryHasProperty(mediaItem, conditionKeyV)) {
97         return;
98     }
99     // get condition string
100     jerry_value_t conditionStrJSValue = jerry_get_property(mediaItem, conditionKeyV);
101     ScopeJSValue autoReleaseV(conditionStrJSValue);
102     char *conditionStr = MallocStringOf(conditionStrJSValue);
103     if (conditionStr == nullptr) {
104         return;
105     }
106     ConditionArbitrator arbitrator;
107     bool isMatched = arbitrator.Decide(conditionStr);
108     ace_free(conditionStr);
109     conditionStr = nullptr;
110     if (!isMatched) {
111         // the current media item is not matching with current device environment
112         return;
113     }
114 
115     // matched, parse the item through normal way
116     InitNormalSelectors(mediaItem, true);
117 }
118 
InitNormalSelectors(const jerry_value_t styleSheetObj,bool overwrite)119 void AppStyleSheet::InitNormalSelectors(const jerry_value_t styleSheetObj, bool overwrite)
120 {
121     // init all id selectors
122     const char * const attrIdSelectors = "idSelectors";
123     jerry_value_t propName = jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(attrIdSelectors)));
124     if (HasOwnProperty(styleSheetObj, propName)) {
125         jerry_value_t propValue = jerry_get_property(styleSheetObj, propName);
126         InitSelectors(&idSelectors_, propValue, false, overwrite);
127         jerry_release_value(propValue);
128     }
129     jerry_release_value(propName);
130 
131     // init all class selectors
132     const char * const attrClassSelectors = "classSelectors";
133     propName = jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(attrClassSelectors)));
134     if (HasOwnProperty(styleSheetObj, propName)) {
135         jerry_value_t propValue = jerry_get_property(styleSheetObj, propName);
136         InitSelectors(&classSelectors_, propValue, false, overwrite);
137         jerry_release_value(propValue);
138     }
139     jerry_release_value(propName);
140 
141     // init styleSheet
142     const char * const keyFrames = "@keyframes";
143     propName = jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(keyFrames)));
144     if (HasOwnProperty(styleSheetObj, propName)) {
145         jerry_value_t propValue = jerry_get_property(styleSheetObj, propName);
146         InitSelectors(&keyFrameSelectors_, propValue, true, overwrite);
147         jerry_release_value(propValue);
148     }
149     jerry_release_value(propName);
150 }
151 
InitSelectors(AppStyleList ** selectorsList,jerry_value_t selectorsObj,bool isKeyFrames,bool overwrite)152 void AppStyleSheet::InitSelectors(AppStyleList **selectorsList, jerry_value_t selectorsObj,
153                                   bool isKeyFrames, bool overwrite)
154 {
155     if (jerry_value_is_undefined(selectorsObj)) {
156         return;
157     }
158 
159     if ((*selectorsList) == nullptr) {
160         (*selectorsList) = new AppStyleList();
161         if ((*selectorsList) == nullptr) {
162             // malloc failed
163             return;
164         }
165     }
166 
167     jerry_value_t styleKeys = jerry_get_object_keys(selectorsObj);
168     uint16_t styleKeySize = jerry_get_array_length(styleKeys);
169     for (uint16_t index = 0; index < styleKeySize; index++) {
170         /* convert style key into char */
171         jerry_value_t styleKey = jerry_get_property_by_index(styleKeys, index);
172         jerry_value_t styleValue = jerry_get_property(selectorsObj, styleKey);
173         AppStyle *newStyle = AppStyle::GenerateFromJS(styleKey, styleValue, isKeyFrames);
174         if (newStyle != nullptr) {
175             AppStyle *existOne = (*selectorsList)->GetExistStyle(newStyle->GetStyleName());
176             if (existOne != nullptr) {
177                 AppStyle::CombineStyles(*existOne, *newStyle, overwrite);
178                 delete newStyle; // combined to exist one, no used
179                 newStyle = nullptr;
180             } else {
181                 (*selectorsList)->AddStyle(newStyle);
182             }
183         }
184         ReleaseJerryValue(styleKey, styleValue, VA_ARG_END_FLAG);
185     }
186 
187     jerry_release_value(styleKeys);
188 }
189 
GetStyleFromIDSelectors(const char * const name) const190 AppStyle *AppStyleSheet::GetStyleFromIDSelectors(const char * const name) const
191 {
192     return GetStyleFromSelectors(idSelectors_, name);
193 }
194 
GetStyleFromClassSelectors(const char * const name) const195 AppStyle *AppStyleSheet::GetStyleFromClassSelectors(const char * const name) const
196 {
197     return GetStyleFromSelectors(classSelectors_, name);
198 }
199 
GetStyleFromKeyFramesSelectors(const char * const name) const200 AppStyle *AppStyleSheet::GetStyleFromKeyFramesSelectors(const char * const name) const
201 {
202     return GetStyleFromSelectors(keyFrameSelectors_, name);
203 }
204 
GetStyleFromSelectors(AppStyleList * selectors,const char * const name) const205 AppStyle *AppStyleSheet::GetStyleFromSelectors(AppStyleList *selectors, const char * const name) const
206 {
207     if ((selectors == nullptr) || (name == nullptr) || strlen(name) == 0) {
208         return nullptr;
209     }
210 
211     AppStyle *first = const_cast<AppStyle *>(selectors->GetFirst());
212     while (first != nullptr) {
213         const char *styleName = first->GetStyleName();
214         if (styleName != nullptr && !strcmp(name, styleName)) {
215             return first;
216         }
217         first = const_cast<AppStyle *>(first->GetNext());
218     }
219 
220     return first;
221 }
222 } // namespace ACELite
223 } // namespace OHOS
224