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