1 /*
2  * Copyright (c) 2023 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 "bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_data_panel_bridge.h"
16 
17 #include "base/geometry/dimension.h"
18 #include "bridge/declarative_frontend/jsview/js_linear_gradient.h"
19 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
20 #include "core/components/common/properties/color.h"
21 #include "core/components/data_panel/data_panel_theme.h"
22 #include "core/components/divider/divider_theme.h"
23 #include "core/components_ng/pattern/gauge/gauge_paint_property.h"
24 #include "frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_utils.h"
25 
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/pattern/data_panel/data_panel_model_ng.h"
28 
29 namespace {
30 const char* DATA_PANEL_NODEPTR_OF_UINODE = "nodePtr_";
31 } // namespace
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr int32_t NUM_0 = 0;
35 constexpr int32_t NUM_1 = 1;
36 constexpr int32_t NUM_2 = 2;
37 
ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient> & colors)38 void ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient>& colors)
39 {
40     RefPtr<DataPanelTheme> theme = ArkTSUtils::GetTheme<DataPanelTheme>();
41     auto themeColors = theme->GetColorsArray();
42     for (const auto& item : themeColors) {
43         OHOS::Ace::NG::Gradient gradient;
44         OHOS::Ace::NG::GradientColor gradientColorStart;
45         gradientColorStart.SetLinearColor(LinearColor(item.first));
46         gradientColorStart.SetDimension(Dimension(0.0));
47         gradient.AddColor(gradientColorStart);
48         OHOS::Ace::NG::GradientColor gradientColorEnd;
49         gradientColorEnd.SetLinearColor(LinearColor(item.second));
50         gradientColorEnd.SetDimension(Dimension(1.0));
51         gradient.AddColor(gradientColorEnd);
52         colors.emplace_back(gradient);
53     }
54 }
55 
ConvertResourceColor(const EcmaVM * vm,const Local<JSValueRef> & item,OHOS::Ace::NG::Gradient & gradient)56 bool ConvertResourceColor(const EcmaVM* vm, const Local<JSValueRef>& item, OHOS::Ace::NG::Gradient& gradient)
57 {
58     Color color;
59     if (!ArkTSUtils::ParseJsColorAlpha(vm, item, color)) {
60         return false;
61     }
62     OHOS::Ace::NG::GradientColor gradientColorStart;
63     gradientColorStart.SetLinearColor(LinearColor(color));
64     gradientColorStart.SetDimension(Dimension(0.0));
65     gradient.AddColor(gradientColorStart);
66     OHOS::Ace::NG::GradientColor gradientColorEnd;
67     gradientColorEnd.SetLinearColor(LinearColor(color));
68     gradientColorEnd.SetDimension(Dimension(1.0));
69     gradient.AddColor(gradientColorEnd);
70     return true;
71 }
72 
ConvertGradientColor(const EcmaVM * vm,const Local<JSValueRef> & itemParam,OHOS::Ace::NG::Gradient & gradient)73 bool ConvertGradientColor(const EcmaVM* vm, const Local<JSValueRef>& itemParam, OHOS::Ace::NG::Gradient& gradient)
74 {
75     if (!itemParam->IsObject(vm)) {
76         return ConvertResourceColor(vm, itemParam, gradient);
77     }
78     Framework::JSLinearGradient* jsLinearGradient =
79         static_cast<Framework::JSLinearGradient*>(itemParam->ToObject(vm)->GetNativePointerField(vm, 0));
80     if (!jsLinearGradient) {
81         return ConvertResourceColor(vm, itemParam, gradient);
82     }
83 
84     size_t colorLength = jsLinearGradient->GetGradient().size();
85     if (colorLength == 0) {
86         return false;
87     }
88     for (size_t colorIndex = 0; colorIndex < colorLength; ++colorIndex) {
89         OHOS::Ace::NG::GradientColor gradientColor;
90         gradientColor.SetLinearColor(LinearColor(jsLinearGradient->GetGradient().at(colorIndex).first));
91         gradientColor.SetDimension(jsLinearGradient->GetGradient().at(colorIndex).second);
92         gradient.AddColor(gradientColor);
93     }
94     return true;
95 }
96 
SetTrackShadowObject(ArkUINodeHandle nativeNode,std::vector<OHOS::Ace::NG::Gradient> & shadowColors,double radius,double offsetX,double offsetY)97 void SetTrackShadowObject(ArkUINodeHandle nativeNode, std::vector<OHOS::Ace::NG::Gradient>& shadowColors,
98     double radius, double offsetX, double offsetY)
99 {
100     ArkUIGradientType gradient;
101     gradient.length = shadowColors.size();
102     auto linearLength = std::make_unique<uint32_t[]>(shadowColors.size());
103     std::vector<uint32_t> allColor;
104     std::vector<ArkUILengthType> allOffset;
105     for (uint32_t i = 0; i < shadowColors.size(); i++) {
106         linearLength[i] = shadowColors[i].GetColors().size();
107         for (uint32_t j = 0; j < linearLength[i]; j++) {
108             allColor.emplace_back(shadowColors[i].GetColors()[j].GetLinearColor().GetValue());
109             allOffset.emplace_back(ArkUILengthType { .number = shadowColors[i].GetColors()[j].GetDimension().Value(),
110                 .unit = static_cast<int8_t>(shadowColors[i].GetColors()[j].GetDimension().Unit()) });
111         }
112     }
113     gradient.color = &(*allColor.begin());
114     gradient.offset = &(*allOffset.begin());
115     gradient.gradientLength = linearLength.get();
116     GetArkUINodeModifiers()->getDataPanelModifier()->setTrackShadow(nativeNode, &gradient, radius, offsetX, offsetY);
117 }
118 } // namespace
119 
SetValueColors(ArkUIRuntimeCallInfo * runtimeCallInfo)120 ArkUINativeModuleValue DataPanelBridge::SetValueColors(ArkUIRuntimeCallInfo* runtimeCallInfo)
121 {
122     EcmaVM* vm = runtimeCallInfo->GetVM();
123     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
124     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(NUM_0);
125     Local<JSValueRef> colors = runtimeCallInfo->GetCallArgRef(NUM_1);
126     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
127 
128     std::vector<OHOS::Ace::NG::Gradient> shadowColors;
129     if (!colors.IsEmpty() && colors->IsArray(vm)) {
130         auto colorsArray = panda::CopyableGlobal<panda::ArrayRef>(vm, colors);
131         for (size_t i = 0; i < colorsArray->Length(vm); ++i) {
132             auto item = colorsArray->GetValueAt(vm, colors, i);
133             OHOS::Ace::NG::Gradient gradient;
134             if (!ConvertGradientColor(vm, item, gradient)) {
135                 shadowColors.clear();
136                 ConvertThemeColor(shadowColors);
137                 break;
138             }
139             shadowColors.emplace_back(gradient);
140         }
141     }
142     ArkUIGradientType gradient;
143     gradient.length = shadowColors.size();
144     auto linearLength = std::make_unique<uint32_t[]>(shadowColors.size());
145     std::vector<uint32_t> allColor;
146     std::vector<ArkUILengthType> allOffset;
147     for (uint32_t i = 0; i < shadowColors.size(); i++) {
148         linearLength[i] = shadowColors[i].GetColors().size();
149         for (uint32_t j = 0; j < linearLength[i]; j++) {
150             allColor.emplace_back(shadowColors[i].GetColors()[j].GetLinearColor().GetValue());
151             allOffset.emplace_back(ArkUILengthType { .number = shadowColors[i].GetColors()[j].GetDimension().Value(),
152                 .unit = static_cast<int8_t>(shadowColors[i].GetColors()[j].GetDimension().Unit()) });
153         }
154     }
155     gradient.color = &(*allColor.begin());
156     gradient.offset = &(*allOffset.begin());
157     gradient.gradientLength = linearLength.get();
158     GetArkUINodeModifiers()->getDataPanelModifier()->setValueColors(nativeNode, &gradient);
159     return panda::JSValueRef::Undefined(vm);
160 }
161 
ResetValueColors(ArkUIRuntimeCallInfo * runtimeCallInfo)162 ArkUINativeModuleValue DataPanelBridge::ResetValueColors(ArkUIRuntimeCallInfo* runtimeCallInfo)
163 {
164     EcmaVM* vm = runtimeCallInfo->GetVM();
165     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
166     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(NUM_0);
167     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
168     GetArkUINodeModifiers()->getDataPanelModifier()->resetValueColors(nativeNode);
169     return panda::JSValueRef::Undefined(vm);
170 }
171 
SetTrackShadow(ArkUIRuntimeCallInfo * runtimeCallInfo)172 ArkUINativeModuleValue DataPanelBridge::SetTrackShadow(ArkUIRuntimeCallInfo* runtimeCallInfo)
173 {
174     EcmaVM* vm = runtimeCallInfo->GetVM();
175     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
176     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(NUM_0);
177     Local<JSValueRef> secondArg = runtimeCallInfo->GetCallArgRef(NUM_1);
178     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
179     if (secondArg->IsNull()) {
180         GetArkUINodeModifiers()->getDataPanelModifier()->setNullTrackShadow(nativeNode);
181         return panda::JSValueRef::Undefined(vm);
182     }
183     if (!secondArg->IsObject(vm)) {
184         GetArkUINodeModifiers()->getDataPanelModifier()->resetTrackShadow(nativeNode);
185         return panda::JSValueRef::Undefined(vm);
186     }
187     auto obj = secondArg->ToObject(vm);
188     auto jsRadius = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "radius"));
189     auto jsOffsetX = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "offsetX"));
190     auto jsOffsetY = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "offsetY"));
191     RefPtr<DataPanelTheme> theme = ArkTSUtils::GetTheme<DataPanelTheme>();
192     double radius = 0.0;
193     if (!ArkTSUtils::ParseJsDouble(vm, jsRadius, radius) || NonPositive(radius)) {
194         radius = theme->GetTrackShadowRadius().ConvertToVp();
195     }
196 
197     double offsetX = 0.0;
198     if (!ArkTSUtils::ParseJsDouble(vm, jsOffsetX, offsetX)) {
199         offsetX = theme->GetTrackShadowOffsetX().ConvertToVp();
200     }
201 
202     double offsetY = 0.0;
203     if (!ArkTSUtils::ParseJsDouble(vm, jsOffsetY, offsetY)) {
204         offsetY = theme->GetTrackShadowOffsetY().ConvertToVp();
205     }
206 
207     auto colors = obj->Get(vm, panda::StringRef::NewFromUtf8(vm, "colors"));
208     std::vector<OHOS::Ace::NG::Gradient> shadowColors;
209     ConvertThemeColor(shadowColors);
210     if (!colors.IsEmpty() && colors->IsArray(vm)) {
211         shadowColors.clear();
212         auto colorsArray = panda::CopyableGlobal<panda::ArrayRef>(vm, colors);
213         for (size_t i = 0; i < colorsArray->Length(vm); ++i) {
214             auto item = colorsArray->GetValueAt(vm, colors, i);
215             OHOS::Ace::NG::Gradient gradient;
216             if (!ConvertGradientColor(vm, item, gradient)) {
217                 shadowColors.clear();
218                 ConvertThemeColor(shadowColors);
219                 break;
220             }
221             shadowColors.emplace_back(gradient);
222         }
223     }
224     SetTrackShadowObject(nativeNode, shadowColors, radius, offsetX, offsetY);
225     return panda::JSValueRef::Undefined(vm);
226 }
227 
ResetTrackShadow(ArkUIRuntimeCallInfo * runtimeCallInfo)228 ArkUINativeModuleValue DataPanelBridge::ResetTrackShadow(ArkUIRuntimeCallInfo* runtimeCallInfo)
229 {
230     EcmaVM* vm = runtimeCallInfo->GetVM();
231     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
232     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(NUM_0);
233     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
234     GetArkUINodeModifiers()->getDataPanelModifier()->resetTrackShadow(nativeNode);
235     return panda::JSValueRef::Undefined(vm);
236 }
SetCloseEffect(ArkUIRuntimeCallInfo * runtimeCallInfo)237 ArkUINativeModuleValue DataPanelBridge::SetCloseEffect(ArkUIRuntimeCallInfo* runtimeCallInfo)
238 {
239     EcmaVM* vm = runtimeCallInfo->GetVM();
240     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
241     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
242     Local<JSValueRef> secondArg = runtimeCallInfo->GetCallArgRef(1);
243     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
244     bool boolValue = secondArg->ToBoolean(vm)->Value();
245     GetArkUINodeModifiers()->getDataPanelModifier()->setCloseEffect(nativeNode, boolValue);
246     return panda::JSValueRef::Undefined(vm);
247 }
248 
ResetCloseEffect(ArkUIRuntimeCallInfo * runtimeCallInfo)249 ArkUINativeModuleValue DataPanelBridge::ResetCloseEffect(ArkUIRuntimeCallInfo* runtimeCallInfo)
250 {
251     EcmaVM* vm = runtimeCallInfo->GetVM();
252     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
253     Local<JSValueRef> nativeNodeArg = runtimeCallInfo->GetCallArgRef(0);
254     auto nativeNode = nodePtr(nativeNodeArg->ToNativePointer(vm)->Value());
255     GetArkUINodeModifiers()->getDataPanelModifier()->resetCloseEffect(nativeNode);
256     return panda::JSValueRef::Undefined(vm);
257 }
258 
SetDataPanelTrackBackgroundColor(ArkUIRuntimeCallInfo * runtimeCallInfo)259 ArkUINativeModuleValue DataPanelBridge::SetDataPanelTrackBackgroundColor(ArkUIRuntimeCallInfo* runtimeCallInfo)
260 {
261     EcmaVM* vm = runtimeCallInfo->GetVM();
262     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
263     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
264     Local<JSValueRef> secondArg = runtimeCallInfo->GetCallArgRef(1);
265     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
266 
267     Color color;
268     if (!ArkTSUtils::ParseJsColorAlpha(vm, secondArg, color)) {
269         RefPtr<DataPanelTheme> theme = ArkTSUtils::GetTheme<DataPanelTheme>();
270         color = theme->GetBackgroundColor();
271     }
272     GetArkUINodeModifiers()->getDataPanelModifier()->setDataPanelTrackBackgroundColor(nativeNode, color.GetValue());
273     return panda::JSValueRef::Undefined(vm);
274 }
275 
ResetDataPanelTrackBackgroundColor(ArkUIRuntimeCallInfo * runtimeCallInfo)276 ArkUINativeModuleValue DataPanelBridge::ResetDataPanelTrackBackgroundColor(ArkUIRuntimeCallInfo* runtimeCallInfo)
277 {
278     EcmaVM* vm = runtimeCallInfo->GetVM();
279     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
280     Local<JSValueRef> nativeNodeArg = runtimeCallInfo->GetCallArgRef(0);
281     auto nativeNode = nodePtr(nativeNodeArg->ToNativePointer(vm)->Value());
282     GetArkUINodeModifiers()->getDataPanelModifier()->resetDataPanelTrackBackgroundColor(nativeNode);
283     return panda::JSValueRef::Undefined(vm);
284 }
285 
SetDataPanelStrokeWidth(ArkUIRuntimeCallInfo * runtimeCallInfo)286 ArkUINativeModuleValue DataPanelBridge::SetDataPanelStrokeWidth(ArkUIRuntimeCallInfo* runtimeCallInfo)
287 {
288     EcmaVM* vm = runtimeCallInfo->GetVM();
289     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
290     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
291     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
292     Local<JSValueRef> jsValue = runtimeCallInfo->GetCallArgRef(1);
293 
294     RefPtr<DataPanelTheme> theme = ArkTSUtils::GetTheme<DataPanelTheme>();
295     CalcDimension strokeWidth;
296 
297     if (!ArkTSUtils::ParseJsDimensionVpNG(vm, jsValue, strokeWidth)) {
298         strokeWidth = theme->GetThickness();
299     }
300 
301     if (jsValue->IsString(vm) && (jsValue->ToString(vm)->ToString(vm).empty() ||
302         !StringUtils::StringToDimensionWithUnitNG(jsValue->ToString(vm)->ToString(vm), strokeWidth))) {
303         strokeWidth = theme->GetThickness();
304     }
305 
306     if (strokeWidth.IsNegative() || strokeWidth.Unit() == DimensionUnit::PERCENT) {
307         strokeWidth = theme->GetThickness();
308     }
309 
310     GetArkUINodeModifiers()->getDataPanelModifier()->setDataPanelStrokeWidth(
311         nativeNode, strokeWidth.Value(), static_cast<int32_t>(strokeWidth.Unit()));
312     return panda::JSValueRef::Undefined(vm);
313 }
314 
ResetDataPanelStrokeWidth(ArkUIRuntimeCallInfo * runtimeCallInfo)315 ArkUINativeModuleValue DataPanelBridge::ResetDataPanelStrokeWidth(ArkUIRuntimeCallInfo* runtimeCallInfo)
316 {
317     EcmaVM* vm = runtimeCallInfo->GetVM();
318     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
319     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(0);
320     auto nativeNode = nodePtr(firstArg->ToNativePointer(vm)->Value());
321     GetArkUINodeModifiers()->getDataPanelModifier()->resetDataPanelStrokeWidth(nativeNode);
322     return panda::JSValueRef::Undefined(vm);
323 }
324 
SetContentModifierBuilder(ArkUIRuntimeCallInfo * runtimeCallInfo)325 ArkUINativeModuleValue DataPanelBridge::SetContentModifierBuilder(ArkUIRuntimeCallInfo* runtimeCallInfo)
326 {
327     EcmaVM* vm = runtimeCallInfo->GetVM();
328     CHECK_NULL_RETURN(vm, panda::NativePointerRef::New(vm, nullptr));
329     Local<JSValueRef> firstArg = runtimeCallInfo->GetCallArgRef(NUM_0);
330     Local<JSValueRef> secondArg = runtimeCallInfo->GetCallArgRef(NUM_1);
331     void* nativeNode = firstArg->ToNativePointer(vm)->Value();
332     auto* frameNode = reinterpret_cast<FrameNode*>(nativeNode);
333     if (!secondArg->IsObject(vm)) {
334         DataPanelModelNG::SetBuilderFunc(frameNode, nullptr);
335         return panda::JSValueRef::Undefined(vm);
336     }
337     panda::CopyableGlobal<panda::ObjectRef> globalObj(vm, secondArg);
338     auto containerId = Container::CurrentId();
339     DataPanelModelNG::SetBuilderFunc(frameNode,
340         [vm, frameNode, globalObj = std::move(globalObj), containerId](
341             DataPanelConfiguration config) -> RefPtr<FrameNode> {
342             ContainerScope scope(containerId);
343             CHECK_NULL_RETURN(Container::Current(), nullptr);
344             CHECK_NULL_RETURN(Container::Current()->GetFrontend(), nullptr);
345             auto context = NapiValueToLocalValue(Container::Current()->GetFrontend()->GetContextValue());
346             auto obj = panda::ObjectRef::New(vm);
347             auto valueArray = panda::ArrayRef::New(vm, config.values_.size());
348             for (uint32_t i = 0; i < config.values_.size(); ++i) {
349                 panda::ArrayRef::SetValueAt(vm, valueArray, i, panda::NumberRef::New(vm, config.values_[i]));
350             }
351             obj->Set(vm, panda::StringRef::NewFromUtf8(vm, "values"), valueArray);
352             obj->Set(vm, panda::StringRef::NewFromUtf8(vm, "maxValue"), panda::NumberRef::New(vm, config.maxValue_));
353             obj->SetNativePointerFieldCount(vm, 1);
354             obj->SetNativePointerField(vm, 0, static_cast<void*>(frameNode));
355             panda::Local<panda::JSValueRef> params[NUM_2] = { context, obj };
356             LocalScope pandaScope(vm);
357             panda::TryCatch trycatch(vm);
358             auto jsObject = globalObj.ToLocal();
359             auto makeFunc = jsObject->Get(vm, panda::StringRef::NewFromUtf8(vm, "makeContentModifierNode"));
360             if (!makeFunc->IsFunction(vm)) { return nullptr; }
361             panda::Local<panda::FunctionRef> func = makeFunc;
362             auto result = func->Call(vm, jsObject, params, 2);
363             JSNApi::ExecutePendingJob(vm);
364             if (result.IsEmpty() || trycatch.HasCaught() || !result->IsObject(vm)) { return nullptr; }
365             auto resultObj = result->ToObject(vm);
366             panda::Local<panda::JSValueRef> nodeptr = resultObj->Get(vm,
367                 panda::StringRef::NewFromUtf8(vm, DATA_PANEL_NODEPTR_OF_UINODE));
368             if (nodeptr.IsEmpty() || nodeptr->IsUndefined() || nodeptr->IsNull()) { return nullptr; }
369             auto* node = nodeptr->ToNativePointer(vm)->Value();
370             auto* frameNode = reinterpret_cast<FrameNode*>(node);
371             CHECK_NULL_RETURN(frameNode, nullptr);
372             return AceType::Claim(frameNode);
373         });
374     return panda::JSValueRef::Undefined(vm);
375 }
376 } // namespace OHOS::Ace::NG
377