• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef SUPPORT_GRAPHICS
17 #include <unicode/localebuilder.h>
18 #include <unicode/locid.h>
19 #include <unicode/utypes.h>
20 #endif
21 #include "locale_matcher.h"
22 #include "res_locale.h"
23 #include "utils/utils.h"
24 #ifdef SUPPORT_GRAPHICS
25 using icu::Locale;
26 using icu::LocaleBuilder;
27 #endif
28 namespace OHOS {
29 namespace Global {
30 namespace Resource {
31 
32 static const std::vector<std::pair<float, ScreenDensity>> resolutions = {
33     { 0.0, ScreenDensity::SCREEN_DENSITY_NOT_SET },
34     { 120.0, ScreenDensity::SCREEN_DENSITY_SDPI },
35     { 160.0, ScreenDensity::SCREEN_DENSITY_MDPI },
36     { 240.0, ScreenDensity::SCREEN_DENSITY_LDPI },
37     { 320.0, ScreenDensity::SCREEN_DENSITY_XLDPI },
38     { 480.0, ScreenDensity::SCREEN_DENSITY_XXLDPI },
39     { 640.0, ScreenDensity::SCREEN_DENSITY_XXXLDPI },
40 };
41 
ResConfigImpl()42 ResConfigImpl::ResConfigImpl()
43     : resLocale_(nullptr),
44     direction_(DIRECTION_NOT_SET),
45     density_(SCREEN_DENSITY_NOT_SET),
46     screenDensityDpi_(SCREEN_DENSITY_NOT_SET),
47     colorMode_(LIGHT),
48     mcc_(MCC_UNDEFINED),
49     mnc_(MNC_UNDEFINED),
50     deviceType_(DEVICE_NOT_SET),
51     inputDevice_(INPUTDEVICE_NOT_SET),
52 #ifdef SUPPORT_GRAPHICS
53     localeInfo_(nullptr),
54 #endif
55     isCompletedScript_(false)
56 {}
57 
58 #ifdef SUPPORT_GRAPHICS
SetLocaleInfo(Locale & localeInfo)59 RState ResConfigImpl::SetLocaleInfo(Locale &localeInfo)
60 {
61     return this->SetLocaleInfo(localeInfo.getLanguage(), localeInfo.getScript(), localeInfo.getCountry());
62 }
63 #endif
64 
SetLocaleInfo(const char * language,const char * script,const char * region)65 RState ResConfigImpl::SetLocaleInfo(const char *language,
66     const char *script,
67     const char *region)
68 {
69 #ifdef SUPPORT_GRAPHICS
70     RState state = SUCCESS;
71     if (Utils::IsStrEmpty(language)) {
72         delete this->resLocale_;
73         delete this->localeInfo_;
74         this->resLocale_ = nullptr;
75         this->localeInfo_ = nullptr;
76         return state;
77     }
78     ResLocale *resLocale =
79         ResLocale::BuildFromParts(language, script, region, state);
80     if (state == SUCCESS) {
81         this->isCompletedScript_ = false;
82         if (script == nullptr || script[0] == '\0') {
83             if (LocaleMatcher::Normalize(resLocale)) {
84                 this->isCompletedScript_ = true;
85             } else {
86                 delete resLocale;
87                 return NOT_ENOUGH_MEM;
88             }
89         }
90         UErrorCode errCode = U_ZERO_ERROR;
91         Locale temp = icu::LocaleBuilder().setLanguage(resLocale->GetLanguage())
92             .setRegion(resLocale->GetRegion()).setScript(resLocale->GetScript()).build(errCode);
93 
94         if (!U_SUCCESS(errCode)) {
95             state = NOT_ENOUGH_MEM;
96             delete resLocale;
97             return state;
98         }
99         delete resLocale_;
100         delete localeInfo_;
101         resLocale_ = resLocale;
102         localeInfo_ = new Locale(temp);
103     }
104 
105     return state;
106 #else
107     return NOT_SUPPORT_SEP;
108 #endif
109 }
110 
SetDeviceType(DeviceType deviceType)111 void ResConfigImpl::SetDeviceType(DeviceType deviceType)
112 {
113     this->deviceType_ = deviceType;
114 }
115 
SetDirection(Direction direction)116 void ResConfigImpl::SetDirection(Direction direction)
117 {
118     this->direction_ = direction;
119 }
120 
SetColorMode(ColorMode colorMode)121 void ResConfigImpl::SetColorMode(ColorMode colorMode)
122 {
123     this->colorMode_ = colorMode;
124 }
125 
SetInputDevice(InputDevice inputDevice)126 void ResConfigImpl::SetInputDevice(InputDevice inputDevice)
127 {
128     this->inputDevice_ = inputDevice;
129 }
130 
SetMcc(uint32_t mcc)131 void ResConfigImpl::SetMcc(uint32_t mcc)
132 {
133     this->mcc_ = mcc;
134 }
135 
SetMnc(uint32_t mnc)136 void ResConfigImpl::SetMnc(uint32_t mnc)
137 {
138     this->mnc_ = mnc;
139 }
140 
ConvertDensity(float density)141 ScreenDensity ResConfigImpl::ConvertDensity(float density)
142 {
143     float deviceDpi = density * Utils::DPI_BASE;
144     auto resolution = SCREEN_DENSITY_NOT_SET;
145     for (const auto& [dpi, value] : resolutions) {
146         resolution = value;
147         if (deviceDpi <= dpi) {
148             break;
149         }
150     }
151     return resolution;
152 }
153 
SetScreenDensity(float screenDensity)154 void ResConfigImpl::SetScreenDensity(float screenDensity)
155 {
156     this->density_ = screenDensity;
157     this->screenDensityDpi_ = ConvertDensity(screenDensity);
158 }
159 
160 #ifdef SUPPORT_GRAPHICS
GetLocaleInfo() const161 const Locale *ResConfigImpl::GetLocaleInfo() const
162 {
163     return localeInfo_;
164 }
165 #endif
166 
GetResLocale() const167 const ResLocale *ResConfigImpl::GetResLocale() const
168 {
169     return this->resLocale_;
170 }
171 
GetDirection() const172 Direction ResConfigImpl::GetDirection() const
173 {
174     return this->direction_;
175 }
176 
GetScreenDensity() const177 float ResConfigImpl::GetScreenDensity() const
178 {
179     return this->density_;
180 }
181 
GetColorMode() const182 ColorMode ResConfigImpl::GetColorMode() const
183 {
184     return this->colorMode_;
185 }
186 
GetInputDevice() const187 InputDevice ResConfigImpl::GetInputDevice() const
188 {
189     return this->inputDevice_;
190 }
191 
GetMcc() const192 uint32_t ResConfigImpl::GetMcc() const
193 {
194     return this->mcc_;
195 }
196 
GetMnc() const197 uint32_t ResConfigImpl::GetMnc() const
198 {
199     return this->mnc_;
200 }
201 
GetDeviceType() const202 DeviceType ResConfigImpl::GetDeviceType() const
203 {
204     return this->deviceType_;
205 }
CopyLocale(ResConfig & other)206 bool ResConfigImpl::CopyLocale(ResConfig &other)
207 {
208 #ifdef SUPPORT_GRAPHICS
209     bool needCopy = false;
210     if (this->GetLocaleInfo() == nullptr && other.GetLocaleInfo() != nullptr) {
211         needCopy = true;
212     }
213     if (this->GetLocaleInfo() != nullptr && other.GetLocaleInfo() == nullptr) {
214         delete this->resLocale_;
215         delete this->localeInfo_;
216         this->resLocale_ = nullptr;
217         this->localeInfo_ = nullptr;
218         return true;
219     }
220     if (this->GetResLocale() != nullptr && other.GetLocaleInfo() != nullptr) {
221         uint64_t encodedLocale = Utils::EncodeLocale(
222             this->GetResLocale()->GetLanguage(),
223             this->GetResLocale()->GetScript(), this->GetResLocale()->GetRegion());
224         uint64_t otherEncodedLocale = Utils::EncodeLocale(
225             other.GetLocaleInfo()->getLanguage(),
226             other.GetLocaleInfo()->getScript(), other.GetLocaleInfo()->getCountry());
227         if (encodedLocale != otherEncodedLocale) {
228             needCopy = true;
229         }
230     }
231     if (needCopy) {
232         ResLocale *temp = new(std::nothrow) ResLocale;
233         if (temp == nullptr) {
234             return false;
235         }
236         RState rs = temp->CopyFromLocaleInfo(other.GetLocaleInfo());
237         if (rs != SUCCESS) {
238             delete temp;
239             return false;
240         }
241         UErrorCode errCode = U_ZERO_ERROR;
242         Locale tempLocale = icu::LocaleBuilder().setLocale(*other.GetLocaleInfo()).build(errCode);
243 
244         if (!U_SUCCESS(errCode)) {
245             delete temp;
246             return false;
247         }
248         delete this->resLocale_;
249         delete this->localeInfo_;
250         this->resLocale_ = temp;
251         this->localeInfo_ = new Locale(tempLocale);
252     }
253     return true;
254 #else
255     return false;
256 #endif
257 }
Copy(ResConfig & other)258 bool ResConfigImpl::Copy(ResConfig &other)
259 {
260     bool isSuccess = this->CopyLocale(other);
261     if (!isSuccess) {
262         return false;
263     }
264     if (this->GetDeviceType() != other.GetDeviceType()) {
265         this->SetDeviceType(other.GetDeviceType());
266     }
267     if (this->GetDirection() != other.GetDirection()) {
268         this->SetDirection(other.GetDirection());
269     }
270     if (this->GetColorMode() != other.GetColorMode()) {
271         this->SetColorMode(other.GetColorMode());
272     }
273     if (this->GetInputDevice() != other.GetInputDevice()) {
274         this->SetInputDevice(other.GetInputDevice());
275     }
276     if (this->GetMcc() != other.GetMcc()) {
277         this->SetMcc(other.GetMcc());
278     }
279     if (this->GetMnc() != other.GetMnc()) {
280         this->SetMnc(other.GetMnc());
281     }
282     if (this->GetScreenDensity() != other.GetScreenDensity()) {
283         this->SetScreenDensity(other.GetScreenDensity());
284     }
285     return true;
286 }
287 
Match(const ResConfigImpl * other) const288 bool ResConfigImpl::Match(const ResConfigImpl *other) const
289 {
290     if (other == nullptr) {
291         return false;
292     }
293     if (!IsMccMncMatch(other->mcc_, other->mnc_)) {
294         return false;
295     }
296     if (!(LocaleMatcher::Match(this->resLocale_, other->GetResLocale()))) {
297         return false;
298     }
299     if (!IsDirectionMatch(other->direction_)) {
300         return false;
301     }
302     if (!IsDeviceTypeMatch(other->deviceType_)) {
303         return false;
304     }
305     if (!IsColorModeMatch(other->colorMode_)) {
306         return false;
307     }
308     if (!IsInputDeviceMatch(other->inputDevice_)) {
309         return false;
310     }
311     return true;
312 }
313 
IsMccMncMatch(uint32_t mcc,uint32_t mnc) const314 bool ResConfigImpl::IsMccMncMatch(uint32_t mcc,  uint32_t mnc) const
315 {
316     if (this->mcc_ != MCC_UNDEFINED && this->mnc_ != MNC_UNDEFINED) {
317         if (mcc != MCC_UNDEFINED && mnc != MNC_UNDEFINED) {
318             if (this->mcc_ != mcc || this->mnc_ != mnc) {
319                 return false;
320             }
321         }
322     } else if (this->mcc_ != MCC_UNDEFINED && this->mnc_ == MNC_UNDEFINED) {
323         if (mcc != MCC_UNDEFINED && this->mcc_ != mcc) {
324             return false;
325         }
326     }
327     return true;
328 }
329 
IsDirectionMatch(Direction direction) const330 bool ResConfigImpl::IsDirectionMatch(Direction direction) const
331 {
332     if (this->direction_ != DIRECTION_NOT_SET && direction != DIRECTION_NOT_SET) {
333         if (this->direction_ != direction) {
334             return false;
335         }
336     }
337     return true;
338 }
339 
IsDeviceTypeMatch(DeviceType deviceType) const340 bool ResConfigImpl::IsDeviceTypeMatch(DeviceType deviceType) const
341 {
342     if (this->deviceType_ != DEVICE_NOT_SET && deviceType != DEVICE_NOT_SET) {
343         if (this->deviceType_ != deviceType) {
344             return false;
345         }
346     }
347     return true;
348 }
349 
IsColorModeMatch(ColorMode colorMode) const350 bool ResConfigImpl::IsColorModeMatch(ColorMode colorMode) const
351 {
352     if (this->colorMode_ != COLOR_MODE_NOT_SET && colorMode != COLOR_MODE_NOT_SET) {
353         if (this->colorMode_ != colorMode) {
354             return false;
355         }
356     }
357     return true;
358 }
359 
IsInputDeviceMatch(InputDevice inputDevice) const360 bool ResConfigImpl::IsInputDeviceMatch(InputDevice inputDevice) const
361 {
362     if (this->inputDevice_ == INPUTDEVICE_NOT_SET && inputDevice != INPUTDEVICE_NOT_SET) {
363         return false;
364     }
365     // reserve for future InputDevice expansion
366     if (this->inputDevice_ != INPUTDEVICE_NOT_SET && inputDevice != INPUTDEVICE_NOT_SET) {
367         if (this->inputDevice_ != inputDevice) {
368             return false;
369         }
370     }
371     return true;
372 }
373 
374 /**
375  * compare this  and target
376  * if this more match request,then return true
377  * else
378  * return false
379  *
380  */
IsMoreSuitable(const ResConfigImpl * other,const ResConfigImpl * request,uint32_t density) const381 bool ResConfigImpl::IsMoreSuitable(const ResConfigImpl *other,
382     const ResConfigImpl *request, uint32_t density) const
383 {
384     if (request != nullptr && other != nullptr) {
385         int ret = IsMccMncMoreSuitable(other->mcc_, other->mnc_, request->mcc_, request->mnc_);
386         if (ret != 0) {
387             return ret > 0;
388         }
389         int8_t result = LocaleMatcher::IsMoreSuitable(this->GetResLocale(), other->GetResLocale(),
390             request->GetResLocale());
391         if (result != 0) {
392             return result > 0;
393         }
394         /**
395          * direction must full match.
396          * when request is set direction and this is not equal other.
397          * this or other oriention is not set.
398          */
399         if (this->direction_ != other->direction_ &&
400             request->direction_ != Direction::DIRECTION_NOT_SET) {
401             return this->direction_ != Direction::DIRECTION_NOT_SET;
402         }
403         if (this->deviceType_ != other->deviceType_ &&
404             request->deviceType_ != DeviceType::DEVICE_NOT_SET) {
405             return this->deviceType_ != DeviceType::DEVICE_NOT_SET;
406         }
407         if (this->colorMode_ != other->colorMode_ &&
408             request->colorMode_ != ColorMode::COLOR_MODE_NOT_SET) {
409             return this->colorMode_ != ColorMode::COLOR_MODE_NOT_SET;
410         }
411         if (this->inputDevice_ != other->inputDevice_ &&
412             request->inputDevice_ != InputDevice::INPUTDEVICE_NOT_SET) {
413             return this->inputDevice_ != InputDevice::INPUTDEVICE_NOT_SET;
414         }
415         ret = IsDensityMoreSuitable(other->screenDensityDpi_, request->screenDensityDpi_, density);
416         if (ret != 0) {
417             return ret > 0;
418         }
419     }
420     return this->IsMoreSpecificThan(other, density);
421 }
422 
423 /**
424  * compare this and target mcc/mnc
425  * if this more match other,then return 1, else if other more match this, return -1,
426  * else
427  * return 0
428  *
429  */
IsMccMncMoreSuitable(uint32_t otherMcc,uint32_t otherMnc,uint32_t requestMcc,uint32_t requestMnc) const430 int ResConfigImpl::IsMccMncMoreSuitable(uint32_t otherMcc, uint32_t otherMnc, uint32_t requestMcc,
431     uint32_t requestMnc) const
432 {
433     int ret = 0;
434     bool defined = requestMcc != MCC_UNDEFINED && requestMnc != MNC_UNDEFINED;
435     bool mccDefined = requestMcc != MCC_UNDEFINED && requestMnc == MNC_UNDEFINED;
436     bool isMccOrMncDiff = this->mcc_ != otherMcc || this->mnc_ != otherMnc;
437     bool isMccDiff = this->mcc_ != otherMcc;
438     if (defined && isMccOrMncDiff) {
439         if ((this->mcc_ != MCC_UNDEFINED) && (this->mnc_ != MNC_UNDEFINED)) {
440             // the mcc/mnc of this resConfig is suitable than other resConfig
441             ret = 1;
442         } else {
443             // the mcc/mnc of other resConfig mcc/mnc is suitable than this resConfig
444             ret = -1;
445         }
446     } else if (mccDefined && isMccDiff) {
447         if (this->mcc_ != MCC_UNDEFINED) {
448             // the mcc of this resConfig is suitable than other resConfig
449             ret = 1;
450         } else {
451             // the mcc of other resConfig is suitable than this resConfig
452             ret = -1;
453         }
454     }
455     return ret;
456 }
457 
458 /**
459  * compare this and target density
460  * if this more match other,then return 1, else if other more match this, return -1,
461  * else
462  * return 0
463  *
464  */
IsDensityMoreSuitable(ScreenDensity otherDensity,ScreenDensity requestDensity,uint32_t density) const465 int ResConfigImpl::IsDensityMoreSuitable(ScreenDensity otherDensity, ScreenDensity requestDensity,
466     uint32_t density) const
467 {
468     int ret = 0;
469     int thisDistance;
470     int otherDistance;
471     if (density == ScreenDensity::SCREEN_DENSITY_NOT_SET) {
472         if (requestDensity != ScreenDensity::SCREEN_DENSITY_NOT_SET &&
473             this->screenDensityDpi_ != otherDensity) {
474             thisDistance = this->screenDensityDpi_ - requestDensity;
475             otherDistance = otherDensity - requestDensity;
476             if (IsDensityMoreSuitable(thisDistance, otherDistance)) {
477                 // the density of this resConfig is suitable than other resConfig
478                 ret = 1;
479             } else {
480                 // the density of other resConfig is suitable than this resConfig
481                 ret = -1;
482             }
483         }
484     } else {
485         if (this->screenDensityDpi_ != otherDensity) {
486             thisDistance = static_cast<int>(this->screenDensityDpi_ - density);
487             otherDistance = static_cast<int>(otherDensity - density);
488             if (IsDensityMoreSuitable(thisDistance, otherDistance)) {
489                 // the density of this resConfig is suitable than other resConfig
490                 ret = 1;
491             } else {
492                 // the density of other resConfig is suitable than this resConfig
493                 ret = -1;
494             }
495         }
496     }
497     return ret;
498 }
499 
IsDensityMoreSuitable(int thisDistance,int otherDistance) const500 bool ResConfigImpl::IsDensityMoreSuitable(int thisDistance, int otherDistance) const
501 {
502     if (thisDistance >= 0 && otherDistance >= 0) {
503         return (thisDistance <= otherDistance);
504     }
505     if (thisDistance > 0) {
506         return true;
507     }
508     if (otherDistance > 0) {
509         return false;
510     }
511     return (thisDistance >= otherDistance);
512 }
513 
~ResConfigImpl()514 ResConfigImpl::~ResConfigImpl()
515 {
516     if (resLocale_ != nullptr) {
517         delete resLocale_;
518         resLocale_ = nullptr;
519     }
520 #ifdef SUPPORT_GRAPHICS
521     if (localeInfo_ != nullptr) {
522         delete localeInfo_;
523         localeInfo_ = nullptr;
524     }
525 #endif
526 }
527 
CompleteScript()528 void ResConfigImpl::CompleteScript()
529 {
530     if (isCompletedScript_) {
531         return;
532     }
533     if (LocaleMatcher::Normalize(this->resLocale_)) {
534         isCompletedScript_ = true;
535     }
536 }
537 
IsCompletedScript() const538 bool ResConfigImpl::IsCompletedScript() const
539 {
540     return isCompletedScript_;
541 }
542 
IsMoreSpecificThan(const ResConfigImpl * other,uint32_t density) const543 bool ResConfigImpl::IsMoreSpecificThan(const ResConfigImpl *other, uint32_t density) const
544 {
545     if (other == nullptr) {
546         return true;
547     }
548     if (this->mcc_ != MCC_UNDEFINED && this->mnc_ != MNC_UNDEFINED) {
549         if (this->mcc_ != other->mcc_ || this->mnc_ != other->mnc_) {
550             return false;
551         }
552     } else if (this->mcc_ != MCC_UNDEFINED && this->mnc_ == MNC_UNDEFINED) {
553         if (this->mcc_ != other->mcc_) {
554             return true;
555         }
556     }
557     int8_t result = LocaleMatcher::IsMoreSpecificThan(
558         this->GetResLocale(),
559         (other == nullptr) ? nullptr : other->GetResLocale());
560     if (result > 0) {
561         return true;
562     }
563     if (result < 0) {
564         return false;
565     }
566     if (this->direction_ != other->direction_) {
567         return (this->direction_ != Direction::DIRECTION_NOT_SET);
568     }
569     if (this->deviceType_ != other->deviceType_) {
570         return (this->deviceType_ != DeviceType::DEVICE_NOT_SET);
571     }
572     if (this->colorMode_ != other->colorMode_) {
573         return (this->colorMode_ != ColorMode::COLOR_MODE_NOT_SET);
574     }
575     if (this->inputDevice_ != other->inputDevice_) {
576         return (this->inputDevice_ == InputDevice::INPUTDEVICE_NOT_SET);
577     }
578     int ret = IsDensityMoreSpecificThan(other->screenDensityDpi_, density);
579     if (ret != 0) {
580         return ret > 0;
581     }
582 
583     return true;
584 }
585 
IsDensityMoreSpecificThan(ScreenDensity otherDensity,uint32_t density) const586 int ResConfigImpl::IsDensityMoreSpecificThan(ScreenDensity otherDensity, uint32_t density) const
587 {
588     int ret = 0;
589     if (density == SCREEN_DENSITY_NOT_SET) {
590         if (this->screenDensityDpi_ != otherDensity) {
591             if (this->screenDensityDpi_ != ScreenDensity::SCREEN_DENSITY_NOT_SET) {
592                 // the density of this resConfig is suitable than other resConfig
593                 ret = 1;
594             } else {
595                 // the density of other resConfig is suitable than this resConfig
596                 ret = -1;
597             }
598         }
599     } else {
600         if ((this->screenDensityDpi_ != ScreenDensity::SCREEN_DENSITY_NOT_SET) &&
601                 (otherDensity == ScreenDensity::SCREEN_DENSITY_NOT_SET)) {
602             // the density of this resConfig is suitable than other resConfig
603             ret = 1;
604         }
605         if ((this->screenDensityDpi_ == ScreenDensity::SCREEN_DENSITY_NOT_SET) &&
606                 (otherDensity != ScreenDensity::SCREEN_DENSITY_NOT_SET)) {
607             // the density of other resConfig is suitable than this resConfig
608             ret = -1;
609         }
610         if (this->screenDensityDpi_ != otherDensity) {
611             int thisDistance = static_cast<int>(this->screenDensityDpi_ - density);
612             int otherDistance = static_cast<int>(otherDensity - density);
613             if (IsDensityMoreSuitable(thisDistance, otherDistance)) {
614                 // the density of this resConfig is suitable than other resConfig
615                 ret = 1;
616             } else {
617                 // the density of other resConfig is suitable than this resConfig
618                 ret = -1;
619             }
620         }
621     }
622     return ret;
623 }
624 
CreateResConfig()625 ResConfig *CreateResConfig()
626 {
627     ResConfigImpl *temp = new(std::nothrow) ResConfigImpl;
628     return temp;
629 }
630 } // namespace Resource
631 } // namespace Global
632 } // namespace OHOS