• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_theme_bridge.h"
17 
18 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_common_bridge.h"
19 #include "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_utils.h"
20 #include "core/components_ng/syntax/with_theme_node.h"
21 #include "core/components_ng/token_theme/token_theme_storage.h"
22 
23 namespace OHOS::Ace::NG {
24 constexpr char DEFAULT_THEME_TAG[] = "ThemeTag";
25 
Create(ArkUIRuntimeCallInfo * runtimeCallInfo)26 ArkUINativeModuleValue ThemeBridge::Create(ArkUIRuntimeCallInfo* runtimeCallInfo)
27 {
28     EcmaVM* vm = runtimeCallInfo->GetVM();
29     CHECK_NULL_RETURN(vm, panda::JSValueRef::Undefined(vm));
30     Local<JSValueRef> themeScopeIdArg = runtimeCallInfo->GetCallArgRef(0);
31     Local<JSValueRef> themeIdArg = runtimeCallInfo->GetCallArgRef(1);
32     Local<JSValueRef> colorsArg = runtimeCallInfo->GetCallArgRef(2); // 2: colorsArg index
33     Local<JSValueRef> darkColorsArg = runtimeCallInfo->GetCallArgRef(3); // 3: darkColorsArg index
34     Local<JSValueRef> colorModeArg = runtimeCallInfo->GetCallArgRef(4); // 4: colorModeArg index
35     Local<JSValueRef> onThemeScopeDestroyArg = runtimeCallInfo->GetCallArgRef(5); // 5: destroy callback arg index
36     Local<JSValueRef> darkSetStatus = runtimeCallInfo->GetCallArgRef(6); // 6: is set darkColors
37 
38     // check all argument valid
39     if (!themeScopeIdArg->IsNumber() || !themeIdArg->IsNumber() || !colorsArg->IsArray(vm) ||
40         !darkSetStatus->IsBoolean() || !colorModeArg->IsNumber() || !onThemeScopeDestroyArg->IsFunction(vm)) {
41         return panda::JSValueRef::Undefined(vm);
42     }
43     ArkUI_Int32 themeScopeId = static_cast<ArkUI_Int32>(themeScopeIdArg->Int32Value(vm));
44     ArkUI_Int32 themeId = static_cast<ArkUI_Int32>(themeIdArg->Int32Value(vm));
45     std::vector<ArkUI_Uint32> lightColors;
46     std::vector<RefPtr<ResourceObject>> lightResObjs;
47     if (!HandleThemeColorsArg(vm, colorsArg, lightColors, lightResObjs, themeId, false)) {
48         TAG_LOGD(AceLogTag::ACE_THEME, "Handle Theme Colors to array failed");
49         return panda::JSValueRef::Undefined(vm);
50     }
51 
52     ArkUI_Bool isDarkSet = static_cast<ArkUI_Bool>(darkSetStatus->BooleaValue(vm));
53     std::vector<ArkUI_Uint32> darkColors;
54     std::vector<RefPtr<ResourceObject>> darkResObjs;
55     if (!isDarkSet) {
56         darkColors = lightColors; // if darkColors is not set, use lightColors
57         darkResObjs = lightResObjs; // if darkColors is not set, use lightResObjs
58     } else if (!darkColorsArg->IsArray(vm) ||
59     !HandleThemeColorsArg(vm, darkColorsArg, darkColors, darkResObjs, themeId, true)) {
60         TAG_LOGD(AceLogTag::ACE_THEME, "Handle Theme darkColors to array failed");
61         return panda::JSValueRef::Undefined(vm);
62     }
63 
64     ArkUI_Int32 colorMode = static_cast<ArkUI_Int32>(colorModeArg->Int32Value(vm));
65     auto obj = onThemeScopeDestroyArg->ToObject(vm);
66     auto containerId = Container::CurrentId();
67     panda::Local<panda::FunctionRef> func = obj;
68     std::function<void()> onThemeScopeDestroy = [vm, func = panda::CopyableGlobal(vm, func), containerId]() {
69         panda::LocalScope pandaScope(vm);
70         panda::TryCatch trycatch(vm);
71         ContainerScope scope(containerId);
72         func->Call(vm, func.ToLocal(), nullptr, 0);
73     };
74 
75     // execute C-API
76     auto themeModifier = GetArkUINodeModifiers()->getThemeModifier();
77     auto theme = themeModifier->createTheme(themeId, lightColors.data(), darkColors.data(), colorMode,
78         static_cast<void*>(&lightResObjs), static_cast<void*>(&darkResObjs));
79     CHECK_NULL_RETURN(theme, panda::NativePointerRef::New(vm, nullptr));
80     ArkUINodeHandle node = themeModifier->getWithThemeNode(themeScopeId);
81     if (!node) {
82         node = CreateWithThemeNode(themeScopeId);
83     }
84     themeModifier->createThemeScope(node, theme);
85     themeModifier->setOnThemeScopeDestroy(node, reinterpret_cast<void*>(&onThemeScopeDestroy));
86 
87     return panda::JSValueRef::Undefined(vm);
88 }
89 
HandleThemeColorsArg(const EcmaVM * vm,const Local<JSValueRef> & colorsArg,std::vector<ArkUI_Uint32> & colors,std::vector<RefPtr<ResourceObject>> & resObjs,ArkUI_Int32 themeId,bool isDark)90 bool ThemeBridge::HandleThemeColorsArg(const EcmaVM* vm, const Local<JSValueRef>& colorsArg,
91     std::vector<ArkUI_Uint32>& colors, std::vector<RefPtr<ResourceObject>>& resObjs,
92     ArkUI_Int32 themeId, bool isDark)
93 {
94     auto basisTheme = TokenThemeStorage::GetInstance()->GetDefaultTheme();
95     if (!basisTheme) {
96         basisTheme = TokenThemeStorage::GetInstance()->ObtainSystemTheme();
97     }
98     if (!basisTheme) {
99         return false;
100     }
101     auto basisObjs = basisTheme->GetResObjs();
102     bool basisObjsAvaliable = basisObjs.size() == TokenColors::TOTAL_NUMBER;
103     for (size_t i = 0; i < TokenColors::TOTAL_NUMBER; i++) {
104         Color color;
105         auto colorParams = panda::ArrayRef::GetValueAt(vm, colorsArg, i);
106         RefPtr<ResourceObject> resObj;
107         bool isColorSetByUser = true;
108         NodeInfo nodeInfo = { DEFAULT_THEME_TAG, ColorMode::COLOR_MODE_UNDEFINED };
109         if (!ArkTSUtils::ParseJsColorAlpha(vm, colorParams, color, resObj, nodeInfo)) {
110             TAG_LOGD(AceLogTag::ACE_THEME, "Parse JS Color Alpha failed");
111             color = basisTheme->Colors()->GetByIndex(i);
112             isColorSetByUser = false;
113             resObj = basisObjsAvaliable ? basisObjs[i] : nullptr;
114         }
115         resObjs.push_back(resObj);
116         colors.push_back(static_cast<ArkUI_Uint32>(color.GetValue()));
117         TokenThemeStorage::GetInstance()->SetIsThemeColorSetByUser(themeId, isDark, i, isColorSetByUser);
118     }
119     return true;
120 }
121 
CreateWithThemeNode(ArkUI_Int32 themeScopeId)122 ArkUINodeHandle ThemeBridge::CreateWithThemeNode(ArkUI_Int32 themeScopeId)
123 {
124     auto themeModifier = GetArkUINodeModifiers()->getThemeModifier();
125     auto node = themeModifier->createWithThemeNode(themeScopeId);
126     RefPtr<WithThemeNode> withThemeNode = AceType::Claim(reinterpret_cast<WithThemeNode*>(node));
127     withThemeNode->DecRefCount();
128     ViewStackProcessor::GetInstance()->Push(withThemeNode);
129     return node;
130 }
131 
Pop(ArkUIRuntimeCallInfo * runtimeCallInfo)132 ArkUINativeModuleValue ThemeBridge::Pop(ArkUIRuntimeCallInfo* runtimeCallInfo)
133 {
134     EcmaVM* vm = runtimeCallInfo->GetVM();
135     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
136     ViewStackProcessor::GetInstance()->PopContainer();
137     return panda::JSValueRef::Undefined(vm);
138 }
139 
SetDefaultTheme(ArkUIRuntimeCallInfo * runtimeCallInfo)140 ArkUINativeModuleValue ThemeBridge::SetDefaultTheme(ArkUIRuntimeCallInfo* runtimeCallInfo)
141 {
142     EcmaVM* vm = runtimeCallInfo->GetVM();
143     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
144     Local<JSValueRef> colorsArg = runtimeCallInfo->GetCallArgRef(0);
145     Local<JSValueRef> isDarkArg = runtimeCallInfo->GetCallArgRef(1);
146 
147     // handle color mode argument
148     if (!isDarkArg->IsBoolean()) {
149         return panda::JSValueRef::Undefined(vm);
150     }
151     ArkUI_Bool isDark = static_cast<ArkUI_Bool>(isDarkArg->BooleaValue(vm));
152 
153     // handle colors argument
154     if (!colorsArg->IsArray(vm)) {
155         return panda::JSValueRef::Undefined(vm);
156     }
157     std::vector<ArkUI_Uint32> colors;
158     std::vector<RefPtr<ResourceObject>> resObjs;
159     auto basisTheme = TokenThemeStorage::GetInstance()->ObtainSystemTheme();
160     for (size_t i = 0; i < TokenColors::TOTAL_NUMBER; i++) {
161         Color color;
162         auto colorParams = panda::ArrayRef::GetValueAt(vm, colorsArg, i);
163         bool isColorAvailable = false;
164         RefPtr<ResourceObject> resObj;
165         NodeInfo nodeInfo = { DEFAULT_THEME_TAG, ColorMode::COLOR_MODE_UNDEFINED };
166         if (!ArkTSUtils::ParseJsColorAlpha(vm, colorParams, color, resObj, nodeInfo)) {
167             TAG_LOGD(AceLogTag::ACE_THEME, "Parse JS Color Alpha failed");
168             if (basisTheme) {
169                 color = basisTheme->Colors()->GetByIndex(i);
170                 isColorAvailable = true;
171             }
172         } else {
173             isColorAvailable = true;
174         }
175         TokenThemeStorage::GetInstance()->SetIsThemeColorAvailable(isDark, i, isColorAvailable);
176         resObjs.emplace_back(resObj);
177         colors.push_back(static_cast<ArkUI_Uint32>(color.GetValue()));
178     }
179 
180     // execute C-API
181     GetArkUINodeModifiers()->getThemeModifier()->setDefaultTheme(colors.data(), isDark, static_cast<void*>(&resObjs));
182     return panda::JSValueRef::Undefined(vm);
183 }
184 
RemoveFromCache(ArkUIRuntimeCallInfo * runtimeCallInfo)185 ArkUINativeModuleValue ThemeBridge::RemoveFromCache(ArkUIRuntimeCallInfo* runtimeCallInfo)
186 {
187     EcmaVM* vm = runtimeCallInfo->GetVM();
188     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
189     Local<JSValueRef> themeIdArg = runtimeCallInfo->GetCallArgRef(0);
190 
191     // handle theme id argument
192     if (!themeIdArg->IsNumber()) {
193         return panda::JSValueRef::Undefined(vm);
194     }
195     ArkUI_Int32 themeId = static_cast<ArkUI_Int32>(themeIdArg->Int32Value(vm));
196 
197     // execute C-API
198     GetArkUINodeModifiers()->getThemeModifier()->removeFromCache(themeId);
199     return panda::JSValueRef::Undefined(vm);
200 }
201 } // namespace OHOS::Ace::NG