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 #include "res_config_impl.h"
16
17 #include <unicode/localebuilder.h>
18 #include <unicode/locid.h>
19
20 #include "locale_matcher.h"
21 #include "res_locale.h"
22 #include "utils/utils.h"
23 using icu::Locale;
24 using icu::LocaleBuilder;
25 namespace OHOS {
26 namespace Global {
27 namespace Resource {
ResConfigImpl()28 ResConfigImpl::ResConfigImpl()
29 : resLocale_(nullptr),
30 direction_(DIRECTION_NOT_SET),
31 screenDensity_(SCREEN_DENSITY_NOT_SET),
32 colorMode_(LIGHT),
33 deviceType_(DEVICE_NOT_SET),
34 isCompletedScript_(false), localeInfo_(nullptr)
35 {}
36
SetLocaleInfo(Locale & localeInfo)37 RState ResConfigImpl::SetLocaleInfo(Locale &localeInfo)
38 {
39 return this->SetLocaleInfo(localeInfo.getLanguage(), localeInfo.getScript(), localeInfo.getCountry());
40 }
41
SetLocaleInfo(const char * language,const char * script,const char * region)42 RState ResConfigImpl::SetLocaleInfo(const char *language,
43 const char *script,
44 const char *region)
45 {
46 RState state = SUCCESS;
47 if (Utils::IsStrEmpty(language)) {
48 delete this->resLocale_;
49 delete this->localeInfo_;
50 this->resLocale_ = nullptr;
51 this->localeInfo_ = nullptr;
52 return state;
53 }
54 ResLocale *resLocale =
55 ResLocale::BuildFromParts(language, script, region, state);
56 if (state == SUCCESS) {
57 this->isCompletedScript_ = false;
58 if (script == nullptr || script[0] == '\0') {
59 if (LocaleMatcher::Normalize(resLocale)) {
60 this->isCompletedScript_ = true;
61 } else {
62 delete resLocale;
63 return NOT_ENOUGH_MEM;
64 }
65 }
66 UErrorCode errCode = U_ZERO_ERROR;
67 Locale temp = icu::LocaleBuilder().setLanguage(resLocale->GetLanguage())
68 .setRegion(resLocale->GetRegion()).setScript(resLocale->GetScript()).build(errCode);
69
70 if (!U_SUCCESS(errCode)) {
71 state = NOT_ENOUGH_MEM;
72 delete resLocale;
73 return state;
74 }
75 delete resLocale_;
76 delete localeInfo_;
77 resLocale_ = resLocale;
78 localeInfo_ = new Locale(temp);
79 }
80
81 return state;
82 }
83
SetDeviceType(DeviceType deviceType)84 void ResConfigImpl::SetDeviceType(DeviceType deviceType)
85 {
86 this->deviceType_ = deviceType;
87 }
88
SetDirection(Direction direction)89 void ResConfigImpl::SetDirection(Direction direction)
90 {
91 this->direction_ = direction;
92 }
93
SetColorMode(ColorMode colorMode)94 void ResConfigImpl::SetColorMode(ColorMode colorMode)
95 {
96 this->colorMode_ = colorMode;
97 }
98
SetScreenDensity(ScreenDensity screenDensity)99 void ResConfigImpl::SetScreenDensity(ScreenDensity screenDensity)
100 {
101 this->screenDensity_ = screenDensity;
102 }
103
GetLocaleInfo() const104 const Locale *ResConfigImpl::GetLocaleInfo() const
105 {
106 return localeInfo_;
107 }
108
GetResLocale() const109 const ResLocale *ResConfigImpl::GetResLocale() const
110 {
111 return this->resLocale_;
112 }
113
GetDirection() const114 Direction ResConfigImpl::GetDirection() const
115 {
116 return this->direction_;
117 }
118
GetScreenDensity() const119 ScreenDensity ResConfigImpl::GetScreenDensity() const
120 {
121 return this->screenDensity_;
122 }
123
GetColorMode() const124 ColorMode ResConfigImpl::GetColorMode() const
125 {
126 return this->colorMode_;
127 }
128
GetDeviceType() const129 DeviceType ResConfigImpl::GetDeviceType() const
130 {
131 return this->deviceType_;
132 }
CopyLocale(ResConfig & other)133 bool ResConfigImpl::CopyLocale(ResConfig &other)
134 {
135 bool needCopy = false;
136 if (this->GetLocaleInfo() == nullptr && other.GetLocaleInfo() != nullptr) {
137 needCopy = true;
138 }
139 if (this->GetLocaleInfo() != nullptr && other.GetLocaleInfo() == nullptr) {
140 delete this->resLocale_;
141 delete this->localeInfo_;
142 this->resLocale_ = nullptr;
143 this->localeInfo_ = nullptr;
144 return true;
145 }
146 if (this->GetResLocale() != nullptr && other.GetLocaleInfo() != nullptr) {
147 uint64_t encodedLocale = Utils::EncodeLocale(
148 this->GetResLocale()->GetLanguage(),
149 this->GetResLocale()->GetScript(), this->GetResLocale()->GetRegion());
150 uint64_t otherEncodedLocale = Utils::EncodeLocale(
151 other.GetLocaleInfo()->getLanguage(),
152 other.GetLocaleInfo()->getScript(), other.GetLocaleInfo()->getCountry());
153 if (encodedLocale != otherEncodedLocale) {
154 needCopy = true;
155 }
156 }
157 if (needCopy) {
158 ResLocale *temp = new(std::nothrow) ResLocale;
159 if (temp == nullptr) {
160 return false;
161 }
162 RState rs = temp->CopyFromLocaleInfo(other.GetLocaleInfo());
163 if (rs != SUCCESS) {
164 delete temp;
165 return false;
166 }
167 UErrorCode errCode = U_ZERO_ERROR;
168 Locale tempLocale = icu::LocaleBuilder().setLocale(*other.GetLocaleInfo()).build(errCode);
169
170 if (!U_SUCCESS(errCode)) {
171 delete temp;
172 return false;
173 }
174 delete this->resLocale_;
175 delete this->localeInfo_;
176 this->resLocale_ = temp;
177 this->localeInfo_ = new Locale(tempLocale);
178 }
179 return true;
180 }
Copy(ResConfig & other)181 bool ResConfigImpl::Copy(ResConfig &other)
182 {
183 bool isSuccess = this->CopyLocale(other);
184 if (!isSuccess) {
185 return false;
186 }
187 if (this->GetDeviceType() != other.GetDeviceType()) {
188 this->SetDeviceType(other.GetDeviceType());
189 }
190 if (this->GetDirection() != other.GetDirection()) {
191 this->SetDirection(other.GetDirection());
192 }
193 if (this->GetColorMode() != other.GetColorMode()) {
194 this->SetColorMode(other.GetColorMode());
195 }
196 if (this->GetScreenDensity() != other.GetScreenDensity()) {
197 this->SetScreenDensity(other.GetScreenDensity());
198 }
199 return true;
200 }
201
Match(const ResConfigImpl * other) const202 bool ResConfigImpl::Match(const ResConfigImpl *other) const
203 {
204 if (other == nullptr) {
205 return false;
206 }
207 if (LocaleMatcher::Match(this->resLocale_, other->GetResLocale()) == false) {
208 return false;
209 }
210 if (this->direction_ != DIRECTION_NOT_SET &&
211 other->direction_ != DIRECTION_NOT_SET) {
212 if (this->direction_ != other->direction_) {
213 return false;
214 }
215 }
216 if (this->deviceType_ != DEVICE_NOT_SET &&
217 other->deviceType_ != DEVICE_NOT_SET) {
218 if (this->deviceType_ != other->deviceType_) {
219 return false;
220 }
221 }
222 if (this->colorMode_ != COLOR_MODE_NOT_SET &&
223 other->colorMode_ != COLOR_MODE_NOT_SET) {
224 if (this->colorMode_ != other->colorMode_) {
225 return false;
226 }
227 }
228 return true;
229 }
230
231 /**
232 * compare this and target
233 * if this more match request,then return true
234 * else
235 * return false
236 *
237 */
IsMoreSuitable(const ResConfigImpl * other,const ResConfigImpl * request) const238 bool ResConfigImpl::IsMoreSuitable(const ResConfigImpl *other,
239 const ResConfigImpl *request) const
240 {
241 if (request != nullptr && other != nullptr) {
242 int8_t result =
243 LocaleMatcher::IsMoreSuitable(this->GetResLocale(), other->GetResLocale(),
244 request->GetResLocale());
245 if (result > 0) {
246 return true;
247 }
248 if (result < 0) {
249 return false;
250 }
251 /**
252 * direction must full match.
253 * when request is set direction and this is not equal other.
254 * this or other oriention is not set.
255 */
256 if (this->direction_ != other->direction_ &&
257 request->direction_ != Direction::DIRECTION_NOT_SET) {
258 return this->direction_ != Direction::DIRECTION_NOT_SET;
259 }
260 if (this->deviceType_ != other->deviceType_ &&
261 request->deviceType_ != DeviceType::DEVICE_NOT_SET) {
262 return this->deviceType_ != DeviceType::DEVICE_NOT_SET;
263 }
264 if (this->colorMode_ != other->colorMode_ &&
265 request->colorMode_ != ColorMode::COLOR_MODE_NOT_SET) {
266 return this->colorMode_ != ColorMode::COLOR_MODE_NOT_SET;
267 }
268 if (request->screenDensity_ != ScreenDensity::SCREEN_DENSITY_NOT_SET &&
269 this->screenDensity_ != other->screenDensity_) {
270 int thisDistance = this->screenDensity_ - request->screenDensity_;
271 int otherDistance = other->screenDensity_ - request->screenDensity_;
272 if (thisDistance >= 0 && otherDistance >= 0) {
273 return (thisDistance <= otherDistance);
274 }
275 if (thisDistance > 0) {
276 return true;
277 }
278 if (otherDistance > 0) {
279 return false;
280 }
281 return (thisDistance >= otherDistance);
282 }
283 }
284 return this->IsMoreSpecificThan(other);
285 }
286
~ResConfigImpl()287 ResConfigImpl::~ResConfigImpl()
288 {
289 delete resLocale_;
290 delete localeInfo_;
291 }
292
CompleteScript()293 void ResConfigImpl::CompleteScript()
294 {
295 if (isCompletedScript_) {
296 return;
297 }
298 if (LocaleMatcher::Normalize(this->resLocale_)) {
299 isCompletedScript_ = true;
300 }
301 }
302
IsCompletedScript() const303 bool ResConfigImpl::IsCompletedScript() const
304 {
305 return isCompletedScript_;
306 }
307
IsMoreSpecificThan(const ResConfigImpl * other) const308 bool ResConfigImpl::IsMoreSpecificThan(const ResConfigImpl *other) const
309 {
310 if (other == nullptr) {
311 return true;
312 }
313 int8_t result = LocaleMatcher::IsMoreSpecificThan(
314 this->GetResLocale(),
315 (other == nullptr) ? nullptr : other->GetResLocale());
316 if (result > 0) {
317 return true;
318 }
319 if (result < 0) {
320 return false;
321 }
322 if (this->direction_ != other->direction_) {
323 return (this->direction_ != Direction::DIRECTION_NOT_SET);
324 }
325 if (this->deviceType_ != other->deviceType_) {
326 return (this->deviceType_ != DeviceType::DEVICE_NOT_SET);
327 }
328 if (this->colorMode_ != other->colorMode_) {
329 return (this->colorMode_ != ColorMode::COLOR_MODE_NOT_SET);
330 }
331 if (this->screenDensity_ != other->screenDensity_) {
332 return (this->screenDensity_ != ScreenDensity::SCREEN_DENSITY_NOT_SET);
333 }
334 return true;
335 }
336
CreateResConfig()337 ResConfig *CreateResConfig()
338 {
339 ResConfigImpl *temp = new(std::nothrow) ResConfigImpl;
340 return temp;
341 }
342 } // namespace Resource
343 } // namespace Global
344 } // namespace OHOS