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 jerry_value_t propValue = UNDEFINED;
125 if (HasOwnProperty(styleSheetObj, propName)) {
126 propValue = jerry_get_property(styleSheetObj, propName);
127 InitSelectors(&idSelectors_, propValue, false, overwrite);
128 jerry_release_value(propValue);
129 }
130 jerry_release_value(propName);
131
132 // init all class selectors
133 const char * const attrClassSelectors = "classSelectors";
134 propName = jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(attrClassSelectors)));
135 if (HasOwnProperty(styleSheetObj, propName)) {
136 propValue = jerry_get_property(styleSheetObj, propName);
137 InitSelectors(&classSelectors_, propValue, false, overwrite);
138 jerry_release_value(propValue);
139 }
140 jerry_release_value(propName);
141
142 // init styleSheet
143 const char * const keyFrames = "@keyframes";
144 propName = jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(keyFrames)));
145 if (HasOwnProperty(styleSheetObj, propName)) {
146 propValue = jerry_get_property(styleSheetObj, propName);
147 InitSelectors(&keyFrameSelectors_, propValue, true, overwrite);
148 jerry_release_value(propValue);
149 }
150 jerry_release_value(propName);
151 }
152
InitSelectors(AppStyleList ** selectorsList,jerry_value_t selectorsObj,bool isKeyFrames,bool overwrite)153 void AppStyleSheet::InitSelectors(AppStyleList **selectorsList, jerry_value_t selectorsObj,
154 bool isKeyFrames, bool overwrite)
155 {
156 if (jerry_value_is_undefined(selectorsObj)) {
157 return;
158 }
159
160 if ((*selectorsList) == nullptr) {
161 (*selectorsList) = new AppStyleList();
162 if ((*selectorsList) == nullptr) {
163 // malloc failed
164 return;
165 }
166 }
167
168 jerry_value_t styleKeys = jerry_get_object_keys(selectorsObj);
169 uint16_t styleKeySize = jerry_get_array_length(styleKeys);
170 for (uint16_t index = 0; index < styleKeySize; index++) {
171 /* convert style key into char */
172 jerry_value_t styleKey = jerry_get_property_by_index(styleKeys, index);
173 jerry_value_t styleValue = jerry_get_property(selectorsObj, styleKey);
174 AppStyle *newStyle = AppStyle::GenerateFromJS(styleKey, styleValue, isKeyFrames);
175 if (newStyle != nullptr) {
176 AppStyle *existOne = (*selectorsList)->GetExistStyle(newStyle->GetStyleName());
177 if (existOne != nullptr) {
178 AppStyle::CombineStyles(*existOne, *newStyle, overwrite);
179 delete newStyle; // combined to exist one, no used
180 newStyle = nullptr;
181 } else {
182 (*selectorsList)->AddStyle(newStyle);
183 }
184 }
185 ReleaseJerryValue(styleKey, styleValue, VA_ARG_END_FLAG);
186 }
187
188 jerry_release_value(styleKeys);
189 }
190
GetStyleFromIDSelectors(const char * const name) const191 AppStyle *AppStyleSheet::GetStyleFromIDSelectors(const char * const name) const
192 {
193 return GetStyleFromSelectors(idSelectors_, name);
194 }
195
GetStyleFromClassSelectors(const char * const name) const196 AppStyle *AppStyleSheet::GetStyleFromClassSelectors(const char * const name) const
197 {
198 return GetStyleFromSelectors(classSelectors_, name);
199 }
200
GetStyleFromKeyFramesSelectors(const char * const name) const201 AppStyle *AppStyleSheet::GetStyleFromKeyFramesSelectors(const char * const name) const
202 {
203 return GetStyleFromSelectors(keyFrameSelectors_, name);
204 }
205
GetStyleFromSelectors(AppStyleList * selectors,const char * const name) const206 AppStyle *AppStyleSheet::GetStyleFromSelectors(AppStyleList *selectors, const char * const name) const
207 {
208 if ((selectors == nullptr) || (name == nullptr) || strlen(name) == 0) {
209 return nullptr;
210 }
211
212 AppStyle *first = const_cast<AppStyle *>(selectors->GetFirst());
213 while (first != nullptr) {
214 const char *styleName = first->GetStyleName();
215 if (styleName != nullptr && !strcmp(name, styleName)) {
216 return first;
217 }
218 first = const_cast<AppStyle *>(first->GetNext());
219 }
220
221 return first;
222 }
223 } // namespace ACELite
224 } // namespace OHOS
225