123b3eb3cSopenharmony_ci/* 223b3eb3cSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 323b3eb3cSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 423b3eb3cSopenharmony_ci * you may not use this file except in compliance with the License. 523b3eb3cSopenharmony_ci * You may obtain a copy of the License at 623b3eb3cSopenharmony_ci * 723b3eb3cSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 823b3eb3cSopenharmony_ci * 923b3eb3cSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1023b3eb3cSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1123b3eb3cSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1223b3eb3cSopenharmony_ci * See the License for the specific language governing permissions and 1323b3eb3cSopenharmony_ci * limitations under the License. 1423b3eb3cSopenharmony_ci */ 1523b3eb3cSopenharmony_ci 1623b3eb3cSopenharmony_ci#include "base/geometry/dimension.h" 1723b3eb3cSopenharmony_ci 1823b3eb3cSopenharmony_ci#include "core/pipeline/pipeline_base.h" 1923b3eb3cSopenharmony_ci 2023b3eb3cSopenharmony_cinamespace OHOS::Ace { 2123b3eb3cSopenharmony_ci 2223b3eb3cSopenharmony_cinamespace { 2323b3eb3cSopenharmony_cistruct CalcDimensionParam { 2423b3eb3cSopenharmony_ci float value = 0.0f; 2523b3eb3cSopenharmony_ci float vpScale = 0.0f; 2623b3eb3cSopenharmony_ci float fpScale = 0.0f; 2723b3eb3cSopenharmony_ci float lpxScale = 0.0f; 2823b3eb3cSopenharmony_ci float parentLength = 0.0f; 2923b3eb3cSopenharmony_ci}; 3023b3eb3cSopenharmony_ci 3123b3eb3cSopenharmony_ciusing CalcDimensionFunc = std::function<bool(const CalcDimensionParam& param, double& result)>; 3223b3eb3cSopenharmony_cibool CalcDimensionNone(const CalcDimensionParam& param, double& result) 3323b3eb3cSopenharmony_ci{ 3423b3eb3cSopenharmony_ci result = param.value; 3523b3eb3cSopenharmony_ci return true; 3623b3eb3cSopenharmony_ci} 3723b3eb3cSopenharmony_ci 3823b3eb3cSopenharmony_cibool CalcDimensionPx(const CalcDimensionParam& param, double& result) 3923b3eb3cSopenharmony_ci{ 4023b3eb3cSopenharmony_ci result = param.value; 4123b3eb3cSopenharmony_ci return true; 4223b3eb3cSopenharmony_ci} 4323b3eb3cSopenharmony_ci 4423b3eb3cSopenharmony_cibool CalcDimensionPercent(const CalcDimensionParam& param, double& result) 4523b3eb3cSopenharmony_ci{ 4623b3eb3cSopenharmony_ci if (NonNegative(param.parentLength)) { 4723b3eb3cSopenharmony_ci result = param.value * param.parentLength; 4823b3eb3cSopenharmony_ci return true; 4923b3eb3cSopenharmony_ci } 5023b3eb3cSopenharmony_ci return false; 5123b3eb3cSopenharmony_ci} 5223b3eb3cSopenharmony_ci 5323b3eb3cSopenharmony_cibool CalcDimensionVp(const CalcDimensionParam& param, double& result) 5423b3eb3cSopenharmony_ci{ 5523b3eb3cSopenharmony_ci if (Positive(param.vpScale)) { 5623b3eb3cSopenharmony_ci result = param.value * param.vpScale; 5723b3eb3cSopenharmony_ci return true; 5823b3eb3cSopenharmony_ci } 5923b3eb3cSopenharmony_ci return false; 6023b3eb3cSopenharmony_ci} 6123b3eb3cSopenharmony_ci 6223b3eb3cSopenharmony_cibool CalcDimensionFp(const CalcDimensionParam& param, double& result) 6323b3eb3cSopenharmony_ci{ 6423b3eb3cSopenharmony_ci if (Positive(param.fpScale) && Positive(param.vpScale)) { 6523b3eb3cSopenharmony_ci result = param.value * param.fpScale * param.vpScale; 6623b3eb3cSopenharmony_ci return true; 6723b3eb3cSopenharmony_ci } 6823b3eb3cSopenharmony_ci return false; 6923b3eb3cSopenharmony_ci} 7023b3eb3cSopenharmony_ci 7123b3eb3cSopenharmony_cibool CalcDimensionLpx(const CalcDimensionParam& param, double& result) 7223b3eb3cSopenharmony_ci{ 7323b3eb3cSopenharmony_ci if (Positive(param.lpxScale)) { 7423b3eb3cSopenharmony_ci result = param.value * param.lpxScale; 7523b3eb3cSopenharmony_ci return true; 7623b3eb3cSopenharmony_ci } 7723b3eb3cSopenharmony_ci return false; 7823b3eb3cSopenharmony_ci} 7923b3eb3cSopenharmony_ci 8023b3eb3cSopenharmony_cistd::unordered_map<DimensionUnit, CalcDimensionFunc> calcDimensionFuncMap_ = { 8123b3eb3cSopenharmony_ci { DimensionUnit::NONE, &CalcDimensionNone }, { DimensionUnit::PX, &CalcDimensionPx }, 8223b3eb3cSopenharmony_ci { DimensionUnit::PERCENT, &CalcDimensionPercent }, { DimensionUnit::VP, &CalcDimensionVp }, 8323b3eb3cSopenharmony_ci { DimensionUnit::FP, &CalcDimensionFp }, { DimensionUnit::LPX, &CalcDimensionLpx } 8423b3eb3cSopenharmony_ci}; 8523b3eb3cSopenharmony_ci} // namespace 8623b3eb3cSopenharmony_ci 8723b3eb3cSopenharmony_cidouble Dimension::ConvertToVp() const 8823b3eb3cSopenharmony_ci{ 8923b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::VP) { 9023b3eb3cSopenharmony_ci return value_; 9123b3eb3cSopenharmony_ci } 9223b3eb3cSopenharmony_ci 9323b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 9423b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, 0.0); 9523b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::NONE) { 9623b3eb3cSopenharmony_ci return value_ / pipeline->GetDipScale(); 9723b3eb3cSopenharmony_ci } 9823b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::PX) { 9923b3eb3cSopenharmony_ci return value_ / pipeline->GetDipScale(); 10023b3eb3cSopenharmony_ci } 10123b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::FP) { 10223b3eb3cSopenharmony_ci return ConvertToVpByAppFontScale(); 10323b3eb3cSopenharmony_ci } 10423b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::LPX) { 10523b3eb3cSopenharmony_ci return value_ * pipeline->GetLogicScale() / pipeline->GetDipScale(); 10623b3eb3cSopenharmony_ci } 10723b3eb3cSopenharmony_ci return 0.0; 10823b3eb3cSopenharmony_ci} 10923b3eb3cSopenharmony_ci 11023b3eb3cSopenharmony_cidouble Dimension::ConvertToPx() const 11123b3eb3cSopenharmony_ci{ 11223b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::NONE) { 11323b3eb3cSopenharmony_ci return value_; 11423b3eb3cSopenharmony_ci } 11523b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::PX) { 11623b3eb3cSopenharmony_ci return value_; 11723b3eb3cSopenharmony_ci } 11823b3eb3cSopenharmony_ci 11923b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 12023b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, 0.0); 12123b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::VP) { 12223b3eb3cSopenharmony_ci return value_ * pipeline->GetDipScale(); 12323b3eb3cSopenharmony_ci } 12423b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::FP) { 12523b3eb3cSopenharmony_ci return ConvertToPxByAppFontScale(0.0f); 12623b3eb3cSopenharmony_ci } 12723b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::LPX) { 12823b3eb3cSopenharmony_ci return value_ * pipeline->GetLogicScale(); 12923b3eb3cSopenharmony_ci } 13023b3eb3cSopenharmony_ci return 0.0; 13123b3eb3cSopenharmony_ci} 13223b3eb3cSopenharmony_ci 13323b3eb3cSopenharmony_cidouble Dimension::ConvertToFp() const 13423b3eb3cSopenharmony_ci{ 13523b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::FP) { 13623b3eb3cSopenharmony_ci return value_; 13723b3eb3cSopenharmony_ci } 13823b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 13923b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, 0.0); 14023b3eb3cSopenharmony_ci auto fontScale = std::clamp(pipeline->GetFontScale(), 0.0f, pipeline->GetMaxAppFontScale()); 14123b3eb3cSopenharmony_ci if (LessOrEqual(fontScale, 0.0)) { 14223b3eb3cSopenharmony_ci return 0.0; 14323b3eb3cSopenharmony_ci } 14423b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::NONE) { 14523b3eb3cSopenharmony_ci return value_ / pipeline->GetDipScale() / fontScale; 14623b3eb3cSopenharmony_ci } 14723b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::PX) { 14823b3eb3cSopenharmony_ci return value_ / pipeline->GetDipScale() / fontScale; 14923b3eb3cSopenharmony_ci } 15023b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::VP) { 15123b3eb3cSopenharmony_ci return value_ / fontScale; 15223b3eb3cSopenharmony_ci } 15323b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::LPX) { 15423b3eb3cSopenharmony_ci return value_ * pipeline->GetLogicScale() / pipeline->GetDipScale() / fontScale; 15523b3eb3cSopenharmony_ci } 15623b3eb3cSopenharmony_ci return 0.0; 15723b3eb3cSopenharmony_ci} 15823b3eb3cSopenharmony_ci 15923b3eb3cSopenharmony_cidouble Dimension::ConvertToPxWithSize(double size) const 16023b3eb3cSopenharmony_ci{ 16123b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::PERCENT) { 16223b3eb3cSopenharmony_ci return value_ * size; 16323b3eb3cSopenharmony_ci } 16423b3eb3cSopenharmony_ci return ConvertToPx(); 16523b3eb3cSopenharmony_ci} 16623b3eb3cSopenharmony_ci 16723b3eb3cSopenharmony_ciDimensionUnit Dimension::GetAdaptDimensionUnit(const Dimension& dimension) 16823b3eb3cSopenharmony_ci{ 16923b3eb3cSopenharmony_ci return static_cast<int32_t>(unit_) <= static_cast<int32_t>(dimension.unit_) ? unit_ : dimension.unit_; 17023b3eb3cSopenharmony_ci} 17123b3eb3cSopenharmony_ci 17223b3eb3cSopenharmony_cidouble Dimension::ConvertToPxDistribute( 17323b3eb3cSopenharmony_ci std::optional<float> minOptional, std::optional<float> maxOptional, bool allowScale) const 17423b3eb3cSopenharmony_ci{ 17523b3eb3cSopenharmony_ci if (unit_ != DimensionUnit::FP) { 17623b3eb3cSopenharmony_ci return ConvertToPx(); 17723b3eb3cSopenharmony_ci } 17823b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 17923b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, value_); 18023b3eb3cSopenharmony_ci if (!allowScale) { 18123b3eb3cSopenharmony_ci return value_ * pipeline->GetDipScale(); 18223b3eb3cSopenharmony_ci } 18323b3eb3cSopenharmony_ci auto minFontScale = minOptional.value_or(0.0f); 18423b3eb3cSopenharmony_ci auto maxFontScale = maxOptional.value_or(static_cast<float>(INT32_MAX)); 18523b3eb3cSopenharmony_ci if (!maxOptional.has_value()) { 18623b3eb3cSopenharmony_ci return ConvertToPxByAppFontScale(minFontScale); 18723b3eb3cSopenharmony_ci } 18823b3eb3cSopenharmony_ci return ConvertToPxByCustomFontScale(minFontScale, maxFontScale); 18923b3eb3cSopenharmony_ci} 19023b3eb3cSopenharmony_ci 19123b3eb3cSopenharmony_cidouble Dimension::ConvertToPxByCustomFontScale(float minFontScale, float maxFontScale) const 19223b3eb3cSopenharmony_ci{ 19323b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 19423b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, value_); 19523b3eb3cSopenharmony_ci float fontScale = std::clamp(pipeline->GetFontScale(), minFontScale, maxFontScale); 19623b3eb3cSopenharmony_ci return value_ * pipeline->GetDipScale() * fontScale; 19723b3eb3cSopenharmony_ci} 19823b3eb3cSopenharmony_ci 19923b3eb3cSopenharmony_cidouble Dimension::ConvertToPxByAppFontScale(float minFontScale) const 20023b3eb3cSopenharmony_ci{ 20123b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 20223b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, value_); 20323b3eb3cSopenharmony_ci float maxFontScale = pipeline->GetMaxAppFontScale(); 20423b3eb3cSopenharmony_ci float fontScale = std::clamp(pipeline->GetFontScale(), minFontScale, maxFontScale); 20523b3eb3cSopenharmony_ci return value_ * pipeline->GetDipScale() * fontScale; 20623b3eb3cSopenharmony_ci} 20723b3eb3cSopenharmony_ci 20823b3eb3cSopenharmony_cidouble Dimension::ConvertToVpByAppFontScale() const 20923b3eb3cSopenharmony_ci{ 21023b3eb3cSopenharmony_ci auto pipeline = PipelineBase::GetCurrentContextSafely(); 21123b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline, value_); 21223b3eb3cSopenharmony_ci CHECK_NULL_RETURN(pipeline->IsFollowSystem(), value_); 21323b3eb3cSopenharmony_ci float maxFontScale = pipeline->GetMaxAppFontScale(); 21423b3eb3cSopenharmony_ci float fontScale = std::clamp(pipeline->GetFontScale(), 0.0f, maxFontScale); 21523b3eb3cSopenharmony_ci return value_ * fontScale; 21623b3eb3cSopenharmony_ci} 21723b3eb3cSopenharmony_ci 21823b3eb3cSopenharmony_cistd::string Dimension::ToString() const 21923b3eb3cSopenharmony_ci{ 22023b3eb3cSopenharmony_ci static const int32_t unitsNum = 6; 22123b3eb3cSopenharmony_ci static const int32_t percentIndex = 3; 22223b3eb3cSopenharmony_ci static const int32_t percentUnit = 100; 22323b3eb3cSopenharmony_ci static std::array<std::string, unitsNum> units = { "px", "vp", "fp", "%", "lpx", "auto" }; 22423b3eb3cSopenharmony_ci if (static_cast<int32_t>(unit_) >= unitsNum || 22523b3eb3cSopenharmony_ci static_cast<int32_t>(unit_) < static_cast<int32_t>(DimensionUnit::INVALID)) { 22623b3eb3cSopenharmony_ci return StringUtils::DoubleToString(value_).append("px"); 22723b3eb3cSopenharmony_ci } 22823b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::NONE) { 22923b3eb3cSopenharmony_ci return StringUtils::DoubleToString(value_).append("none"); 23023b3eb3cSopenharmony_ci } 23123b3eb3cSopenharmony_ci if (unit_ == DimensionUnit::INVALID) { 23223b3eb3cSopenharmony_ci return StringUtils::DoubleToString(value_).append("invalid"); 23323b3eb3cSopenharmony_ci } 23423b3eb3cSopenharmony_ci if (units[static_cast<int>(unit_)] == units[percentIndex]) { 23523b3eb3cSopenharmony_ci return StringUtils::DoubleToString(value_ * percentUnit).append(units[static_cast<int>(unit_)]); 23623b3eb3cSopenharmony_ci } 23723b3eb3cSopenharmony_ci return StringUtils::DoubleToString(value_).append(units[static_cast<int>(unit_)]); 23823b3eb3cSopenharmony_ci} 23923b3eb3cSopenharmony_ci 24023b3eb3cSopenharmony_ci// for example str = 0.00px 24123b3eb3cSopenharmony_ciDimension Dimension::FromString(const std::string& str) 24223b3eb3cSopenharmony_ci{ 24323b3eb3cSopenharmony_ci static const int32_t percentUnit = 100; 24423b3eb3cSopenharmony_ci static const std::unordered_map<std::string, DimensionUnit> uMap { 24523b3eb3cSopenharmony_ci { "px", DimensionUnit::PX }, 24623b3eb3cSopenharmony_ci { "vp", DimensionUnit::VP }, 24723b3eb3cSopenharmony_ci { "fp", DimensionUnit::FP }, 24823b3eb3cSopenharmony_ci { "%", DimensionUnit::PERCENT }, 24923b3eb3cSopenharmony_ci { "lpx", DimensionUnit::LPX }, 25023b3eb3cSopenharmony_ci { "auto", DimensionUnit::AUTO }, 25123b3eb3cSopenharmony_ci }; 25223b3eb3cSopenharmony_ci 25323b3eb3cSopenharmony_ci double value = 0.0; 25423b3eb3cSopenharmony_ci DimensionUnit unit = DimensionUnit::FP; 25523b3eb3cSopenharmony_ci 25623b3eb3cSopenharmony_ci if (str.empty()) { 25723b3eb3cSopenharmony_ci LOGE("UITree |ERROR| empty string"); 25823b3eb3cSopenharmony_ci return Dimension(value, unit); 25923b3eb3cSopenharmony_ci } 26023b3eb3cSopenharmony_ci 26123b3eb3cSopenharmony_ci for (int32_t i = static_cast<int32_t>(str.length() - 1); i >= 0; --i) { 26223b3eb3cSopenharmony_ci if (str[i] >= '0' && str[i] <= '9') { 26323b3eb3cSopenharmony_ci value = StringUtils::StringToDouble(str.substr(0, i + 1)); 26423b3eb3cSopenharmony_ci auto subStr = str.substr(i + 1); 26523b3eb3cSopenharmony_ci auto iter = uMap.find(subStr); 26623b3eb3cSopenharmony_ci if (iter != uMap.end()) { 26723b3eb3cSopenharmony_ci unit = iter->second; 26823b3eb3cSopenharmony_ci } 26923b3eb3cSopenharmony_ci value = unit == DimensionUnit::PERCENT ? value / percentUnit : value; 27023b3eb3cSopenharmony_ci break; 27123b3eb3cSopenharmony_ci } 27223b3eb3cSopenharmony_ci } 27323b3eb3cSopenharmony_ci return Dimension(value, unit); 27423b3eb3cSopenharmony_ci} 27523b3eb3cSopenharmony_ci 27623b3eb3cSopenharmony_cibool Dimension::NormalizeToPx( 27723b3eb3cSopenharmony_ci double vpScale, double fpScale, double lpxScale, double parentLength, double& result) const 27823b3eb3cSopenharmony_ci{ 27923b3eb3cSopenharmony_ci auto func = calcDimensionFuncMap_.find(unit_); 28023b3eb3cSopenharmony_ci if (func != calcDimensionFuncMap_.end()) { 28123b3eb3cSopenharmony_ci CalcDimensionParam param = { value_, vpScale, fpScale, lpxScale, parentLength }; 28223b3eb3cSopenharmony_ci return func->second(param, result); 28323b3eb3cSopenharmony_ci } 28423b3eb3cSopenharmony_ci return false; 28523b3eb3cSopenharmony_ci} 28623b3eb3cSopenharmony_ci} // namespace OHOS::Ace 287