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