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 {
Create(ArkUIRuntimeCallInfo * runtimeCallInfo)24 ArkUINativeModuleValue ThemeBridge::Create(ArkUIRuntimeCallInfo* runtimeCallInfo)
25 {
26 EcmaVM* vm = runtimeCallInfo->GetVM();
27 CHECK_NULL_RETURN(vm, panda::JSValueRef::Undefined(vm));
28 Local<JSValueRef> themeScopeIdArg = runtimeCallInfo->GetCallArgRef(0);
29 Local<JSValueRef> themeIdArg = runtimeCallInfo->GetCallArgRef(1);
30 Local<JSValueRef> colorsArg = runtimeCallInfo->GetCallArgRef(2); // 2: colorsArg index
31 Local<JSValueRef> colorModeArg = runtimeCallInfo->GetCallArgRef(3); // 3: colorModeArg index
32 Local<JSValueRef> onThemeScopeDestroyArg = runtimeCallInfo->GetCallArgRef(4); // 4: destroy callback arg index
33
34 // handle theme scope id argument
35 if (!themeScopeIdArg->IsNumber()) {
36 return panda::JSValueRef::Undefined(vm);
37 }
38 ArkUI_Int32 themeScopeId = static_cast<ArkUI_Int32>(themeScopeIdArg->Int32Value(vm));
39
40 // handle theme id argument
41 if (!themeIdArg->IsNumber()) {
42 return panda::JSValueRef::Undefined(vm);
43 }
44 ArkUI_Int32 themeId = static_cast<ArkUI_Int32>(themeIdArg->Int32Value(vm));
45
46 // handle colors argument
47 if (!colorsArg->IsArray(vm)) {
48 return panda::JSValueRef::Undefined(vm);
49 }
50 std::vector<ArkUI_Uint32> colors;
51 if (!HandleThemeColorsArg(vm, colorsArg, colors)) {
52 return panda::JSValueRef::Undefined(vm);
53 }
54
55 // handle color mode argument
56 if (!colorModeArg->IsNumber()) {
57 return panda::JSValueRef::Undefined(vm);
58 }
59 ArkUI_Int32 colorMode = static_cast<ArkUI_Int32>(colorModeArg->Int32Value(vm));
60
61 // handle on theme scope destroy argument
62 if (!onThemeScopeDestroyArg->IsFunction(vm)) {
63 return panda::JSValueRef::Undefined(vm);
64 }
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, colors.data(), colorMode);
78 CHECK_NULL_RETURN(theme, panda::NativePointerRef::New(vm, nullptr));
79 ArkUINodeHandle node = themeModifier->getWithThemeNode(themeScopeId);
80 if (!node) {
81 node = CreateWithThemeNode(themeScopeId);
82 }
83 themeModifier->createThemeScope(node, theme);
84 themeModifier->setOnThemeScopeDestroy(node, reinterpret_cast<void*>(&onThemeScopeDestroy));
85
86 return panda::JSValueRef::Undefined(vm);
87 }
88
HandleThemeColorsArg(const EcmaVM * vm,const Local<JSValueRef> & colorsArg,std::vector<ArkUI_Uint32> & colors)89 bool ThemeBridge::HandleThemeColorsArg(const EcmaVM* vm, const Local<JSValueRef>& colorsArg,
90 std::vector<ArkUI_Uint32>& colors)
91 {
92 auto basisTheme = TokenThemeStorage::GetInstance()->GetDefaultTheme();
93 if (!basisTheme) {
94 basisTheme = TokenThemeStorage::GetInstance()->ObtainSystemTheme();
95 }
96 if (!basisTheme) {
97 return false;
98 }
99 for (size_t i = 0; i < TokenColors::TOTAL_NUMBER; i++) {
100 Color color;
101 auto colorParams = panda::ArrayRef::GetValueAt(vm, colorsArg, i);
102 if (!ArkTSUtils::ParseJsColorAlpha(vm, colorParams, color)) {
103 color = basisTheme->Colors()->GetByIndex(i);
104 }
105 colors.push_back(static_cast<ArkUI_Uint32>(color.GetValue()));
106 }
107 return true;
108 }
109
CreateWithThemeNode(ArkUI_Int32 themeScopeId)110 ArkUINodeHandle ThemeBridge::CreateWithThemeNode(ArkUI_Int32 themeScopeId)
111 {
112 auto themeModifier = GetArkUINodeModifiers()->getThemeModifier();
113 auto node = themeModifier->createWithThemeNode(themeScopeId);
114 RefPtr<WithThemeNode> withThemeNode = AceType::Claim(reinterpret_cast<WithThemeNode*>(node));
115 withThemeNode->DecRefCount();
116 ViewStackProcessor::GetInstance()->Push(withThemeNode);
117 return node;
118 }
119
Pop(ArkUIRuntimeCallInfo * runtimeCallInfo)120 ArkUINativeModuleValue ThemeBridge::Pop(ArkUIRuntimeCallInfo* runtimeCallInfo)
121 {
122 EcmaVM* vm = runtimeCallInfo->GetVM();
123 CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
124 ViewStackProcessor::GetInstance()->PopContainer();
125 return panda::JSValueRef::Undefined(vm);
126 }
127
SetDefaultTheme(ArkUIRuntimeCallInfo * runtimeCallInfo)128 ArkUINativeModuleValue ThemeBridge::SetDefaultTheme(ArkUIRuntimeCallInfo* runtimeCallInfo)
129 {
130 EcmaVM* vm = runtimeCallInfo->GetVM();
131 CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
132 Local<JSValueRef> colorsArg = runtimeCallInfo->GetCallArgRef(0);
133 Local<JSValueRef> isDarkArg = runtimeCallInfo->GetCallArgRef(1);
134
135 // handle color mode argument
136 if (!isDarkArg->IsBoolean()) {
137 return panda::JSValueRef::Undefined(vm);
138 }
139 ArkUI_Bool isDark = static_cast<ArkUI_Bool>(isDarkArg->BooleaValue(vm));
140
141 // handle colors argument
142 if (!colorsArg->IsArray(vm)) {
143 return panda::JSValueRef::Undefined(vm);
144 }
145 std::vector<ArkUI_Uint32> colors;
146 auto basisTheme = TokenThemeStorage::GetInstance()->ObtainSystemTheme();
147 for (size_t i = 0; i < TokenColors::TOTAL_NUMBER; i++) {
148 Color color;
149 auto colorParams = panda::ArrayRef::GetValueAt(vm, colorsArg, i);
150 bool isColorAvailable = false;
151 if (!ArkTSUtils::ParseJsColorAlpha(vm, colorParams, color)) {
152 if (basisTheme) {
153 color = basisTheme->Colors()->GetByIndex(i);
154 isColorAvailable = true;
155 }
156 } else {
157 isColorAvailable = true;
158 }
159 TokenThemeStorage::GetInstance()->SetIsThemeColorAvailable(isDark, i, isColorAvailable);
160
161 colors.push_back(static_cast<ArkUI_Uint32>(color.GetValue()));
162 }
163
164 // execute C-API
165 GetArkUINodeModifiers()->getThemeModifier()->setDefaultTheme(colors.data(), isDark);
166 return panda::JSValueRef::Undefined(vm);
167 }
168
RemoveFromCache(ArkUIRuntimeCallInfo * runtimeCallInfo)169 ArkUINativeModuleValue ThemeBridge::RemoveFromCache(ArkUIRuntimeCallInfo* runtimeCallInfo)
170 {
171 EcmaVM* vm = runtimeCallInfo->GetVM();
172 CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
173 Local<JSValueRef> themeIdArg = runtimeCallInfo->GetCallArgRef(0);
174
175 // handle theme id argument
176 if (!themeIdArg->IsNumber()) {
177 return panda::JSValueRef::Undefined(vm);
178 }
179 ArkUI_Int32 themeId = static_cast<ArkUI_Int32>(themeIdArg->Int32Value(vm));
180
181 // execute C-API
182 GetArkUINodeModifiers()->getThemeModifier()->removeFromCache(themeId);
183 return panda::JSValueRef::Undefined(vm);
184 }
185 } // namespace OHOS::Ace::NG