1 /*
2  * Copyright (c) 2021-2022 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_THEME_THEME_STYLE_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_THEME_THEME_STYLE_H
18 
19 #include <string>
20 #include <type_traits>
21 #include <unordered_map>
22 #include <variant>
23 #include <future>
24 #include <mutex>
25 #include <shared_mutex>
26 
27 #include "base/geometry/dimension.h"
28 #include "base/log/log.h"
29 #include "base/memory/ace_type.h"
30 #include "base/resource/internal_resource.h"
31 #include "core/components/common/properties/color.h"
32 #include "core/components/theme/theme_utils.h"
33 
34 namespace OHOS::Ace {
35 
36 class ThemeStyle;
37 class ThemeUtils;
38 class StateResource;
39 
40 using ResRawValue = std::variant<Color, Dimension, int32_t, uint32_t, double, InternalResource::ResourceId, std::string,
41     RefPtr<ThemeStyle>, RefPtr<StateResource>>;
42 using BlendAlpha = std::variant<double, uint32_t>;
43 
44 enum class ThemeConstantsType {
45     // Error type for check if key is match with value
46     ERROR = -1,
47     COLOR = 0,
48     DIMENSION,
49     INT,
50     DOUBLE,
51     RESOURCE_ID,
52     REFERENCE,
53     REFERENCE_ATTR,
54     STRING,
55     PATTERN,
56     STATE_RESOURCE,
57     THEME,
58 };
59 
60 struct ResValueWrapper {
61     template<typename T>
GetValueResValueWrapper62     std::pair<bool, T> GetValue(const T& errorValue) const
63     {
64         auto valuePtr = std::get_if<T>(&value);
65         if (!valuePtr) {
66             return std::make_pair(false, errorValue);
67         }
68         return std::make_pair(true, *valuePtr);
69     }
70 
71     ThemeConstantsType type { ThemeConstantsType::COLOR };
72     ResRawValue value;
73     // Whether style value is public to app.
74     bool isPublic { false };
75     // Extra alpha needs to blend with color(uint means an ID reference, double means an alpha value).
76     BlendAlpha blendAlpha { 1.0 };
77 };
78 
79 using ThemeConstantsMap = std::unordered_map<uint32_t, ResValueWrapper>;
80 
81 class ThemeStyle : public virtual AceType {
82     DECLARE_ACE_TYPE(ThemeStyle, AceType);
83 
84 private:
85     mutable std::shared_mutex attributesMutex_;
86 
87 public:
88     ThemeStyle() = default;
~ThemeStyle()89     ~ThemeStyle() override
90     {
91         attributes_.clear();
92     }
93 
SetName(const std::string & name)94     void SetName(const std::string& name)
95     {
96         name_ = name;
97     }
98 
GetName()99     std::string GetName() const
100     {
101         return name_;
102     }
103 
ParseContent()104     virtual void ParseContent() {}
105 
SetAttributes(const std::unordered_map<std::string,ResValueWrapper> & attributes)106     void SetAttributes(const std::unordered_map<std::string, ResValueWrapper>& attributes)
107     {
108         std::unique_lock<std::shared_mutex> lock(attributesMutex_);
109         attributes_ = attributes;
110     }
111 
GetAttributes()112     const std::unordered_map<std::string, ResValueWrapper>& GetAttributes() const
113     {
114         std::shared_lock<std::shared_mutex> lock(attributesMutex_);
115         return attributes_;
116     }
117 
HasAttr(const std::string & attr)118     bool HasAttr(const std::string& attr) const
119     {
120         std::shared_lock<std::shared_mutex> lock(attributesMutex_);
121         return attributes_.find(attr) != attributes_.end();
122     }
123 
SetAttr(const std::string & attr,const ResValueWrapper & value)124     void SetAttr(const std::string& attr, const ResValueWrapper& value)
125     {
126         std::unique_lock<std::shared_mutex> lock(attributesMutex_);
127         attributes_[attr] = value;
128     }
CheckThemeStyleLoaded(const std::string & patternName)129     virtual void CheckThemeStyleLoaded(const std::string& patternName) {}
130     template<typename T>
GetAttr(const std::string & attr,const T & errorValue)131     T GetAttr(const std::string& attr, const T& errorValue) const
132     {
133         std::shared_lock<std::shared_mutex> lock(attributesMutex_);
134         auto findIter = attributes_.find(attr);
135         if (findIter == attributes_.end()) {
136             TAG_LOGW(AceLogTag::ACE_THEME, "style %{public}s not contains %{public}s!", name_.c_str(), attr.c_str());
137             return errorValue;
138         }
139         const auto& valueWrapper = findIter->second;
140         // parse attr reference.
141         if (valueWrapper.type == ThemeConstantsType::REFERENCE_ATTR) {
142             auto parent = parentStyle_.Upgrade();
143             if (!parent) {
144                 return errorValue;
145             }
146             auto parseResult = ThemeUtils::ParseThemeIdReference(valueWrapper.GetValue<std::string>("").second);
147             if (!parseResult.parseSuccess || parseResult.isIdRef) {
148                 return errorValue;
149             }
150             return parent->GetAttr<T>(parseResult.refAttr, errorValue);
151         }
152         auto valuePair = valueWrapper.GetValue<T>(errorValue);
153         if (!valuePair.first) {
154             TAG_LOGW(AceLogTag::ACE_THEME, "style %{public}s get attr %{public}s error!", name_.c_str(), attr.c_str());
155         }
156         return valuePair.second;
157     }
158 
159 protected:
160     std::string name_;
161     std::unordered_map<std::string, ResValueWrapper> attributes_;
162     WeakPtr<ThemeStyle> parentStyle_;
163 };
164 
165 class StateResource : public virtual AceType {
166     DECLARE_ACE_TYPE(StateResource, AceType);
167 
168 public:
169     StateResource() = default;
170     ~StateResource() override = default;
171 
SetName(const std::string & name)172     void SetName(const std::string& name)
173     {
174         name_ = name;
175     }
176 
SetStateValue(uint32_t state,const ResValueWrapper & value)177     void SetStateValue(uint32_t state, const ResValueWrapper& value)
178     {
179         states_[state] = value;
180     }
181 
182     template<typename T>
GetState(uint32_t state,const T & defaultValue)183     T GetState(uint32_t state, const T& defaultValue) const
184     {
185         auto findIter = states_.find(state);
186         if (findIter == states_.end()) {
187             return defaultValue;
188         }
189         auto valuePair = findIter->second.GetValue<T>(defaultValue);
190         if (!valuePair.first) {
191             TAG_LOGW(AceLogTag::ACE_THEME, "style %{public}s get state %{public}u error!", name_.c_str(), state);
192         }
193         return valuePair.second;
194     }
195 
196 private:
197     std::string name_;
198     std::unordered_map<uint32_t, ResValueWrapper> states_;
199 };
200 
201 } // namespace OHOS::Ace
202 
203 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_THEME_THEME_STYLE_H
204