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/cj_frontend/interfaces/cj_ffi/cj_customdialog_controller_ffi.h"
17 
18 #include "cj_lambda.h"
19 
20 #include "bridge/cj_frontend/interfaces/cj_ffi/utils.h"
21 #include "bridge/common/utils/utils.h"
22 #include "core/components_ng/base/view_stack_processor.h"
23 #include "core/pipeline_ng/pipeline_context.h"
24 #include "frameworks/base/memory/referenced.h"
25 #include "frameworks/bridge/common/utils/engine_helper.h"
26 
27 using namespace OHOS::Ace;
28 using namespace OHOS::FFI;
29 using namespace OHOS::Ace::Framework;
30 
31 namespace {
32 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
33     DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
34     DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
35     DialogAlignment::BOTTOM_END };
36 }
37 
38 namespace OHOS::Ace::Framework {
ParseCjCustomDialogControllerOffset(DimensionOffset & offset,NativeCustomDialogControllerOptions options)39 void ParseCjCustomDialogControllerOffset(DimensionOffset& offset, NativeCustomDialogControllerOptions options)
40 {
41     CalcDimension dx(options.offset.dx.value, static_cast<DimensionUnit>(options.offset.dx.unitType));
42     CalcDimension dy(options.offset.dy.value, static_cast<DimensionUnit>(options.offset.dy.unitType));
43     dx.ResetInvalidValue();
44     dy.ResetInvalidValue();
45     offset.SetX(dx);
46     offset.SetY(dy);
47 }
48 
ParseCjCustomDialogControllerMaskRect(DimensionRect & rect,NativeCustomDialogControllerOptions options)49 void ParseCjCustomDialogControllerMaskRect(DimensionRect& rect, NativeCustomDialogControllerOptions options)
50 {
51     Dimension rectX(options.maskRect.x, static_cast<DimensionUnit>(options.maskRect.xUnit));
52     Dimension rectY(options.maskRect.y, static_cast<DimensionUnit>(options.maskRect.yUnit));
53     Dimension rectWidth(options.maskRect.width, static_cast<DimensionUnit>(options.maskRect.widthUnit));
54     Dimension rectHeight(options.maskRect.height, static_cast<DimensionUnit>(options.maskRect.heightUnit));
55     DimensionOffset rectOffset(rectX, rectY);
56     rect.SetWidth(rectWidth);
57     rect.SetHeight(rectHeight);
58     rect.SetOffset(rectOffset);
59 }
60 
ParseCjCustomDialogControllerBorderRadius(NG::BorderRadiusProperty & radius,NativeCustomDialogControllerOptions options)61 void ParseCjCustomDialogControllerBorderRadius(
62     NG::BorderRadiusProperty& radius, NativeCustomDialogControllerOptions options)
63 {
64     CalcDimension radiusCalc(options.cornerRadius.value, static_cast<DimensionUnit>(options.cornerRadius.unitType));
65     radius.radiusTopLeft = radiusCalc;
66     radius.radiusTopRight = radiusCalc;
67     radius.radiusBottomLeft = radiusCalc;
68     radius.radiusBottomRight = radiusCalc;
69     radius.multiValued = true;
70 }
71 
NativeCustomDialogController(NativeCustomDialogControllerOptions options)72 NativeCustomDialogController::NativeCustomDialogController(NativeCustomDialogControllerOptions options) : FFIData()
73 {
74     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
75     cancelFunction_ = CJLambda::Create(options.cancel);
76     auto onCancel = [cjCallback = cancelFunction_, node = frameNode]() {
77         auto pipelineContext = PipelineContext::GetCurrentContext();
78         CHECK_NULL_VOID(pipelineContext);
79         pipelineContext->UpdateCurrentActiveNode(node);
80         cjCallback();
81     };
82     dialogProperties_.onCancel = onCancel;
83     dialogProperties_.autoCancel = options.autoCancel;
84     dialogProperties_.customStyle = options.customStyle;
85     dialogProperties_.alignment = DIALOG_ALIGNMENT[options.alignment];
86     DimensionOffset offset_;
87     ParseCjCustomDialogControllerOffset(offset_, options);
88     dialogProperties_.offset = offset_;
89     if (options.gridCount.hasValue) {
90         dialogProperties_.gridCount = options.gridCount.value;
91     }
92     dialogProperties_.maskColor = Color(options.maskColor);
93     DimensionRect dimenRect;
94     ParseCjCustomDialogControllerMaskRect(dimenRect, options);
95     dialogProperties_.maskRect = dimenRect;
96     if (options.backgroundColor.hasValue) {
97         dialogProperties_.backgroundColor = Color(options.backgroundColor.value);
98     }
99     NG::BorderRadiusProperty radius;
100     ParseCjCustomDialogControllerBorderRadius(radius, options);
101     dialogProperties_.borderRadius = radius;
102     if (options.openAnimation.hasValue) {
103         AnimationOption openAnimation;
104         ParseCjAnimation(options.openAnimation.value, openAnimation);
105         dialogProperties_.openAnimation = openAnimation;
106     }
107     if (options.closeAnimation.hasValue) {
108         AnimationOption closeAnimation;
109         ParseCjAnimation(options.closeAnimation.value, closeAnimation);
110         dialogProperties_.closeAnimation = closeAnimation;
111     }
112 #if defined(PREVIEW)
113     LOGW("[Engine Log] Unable to use the SubWindow in the Previewer. Perform this operation on the "
114          "emulator or a real device instead.");
115 #else
116     dialogProperties_.isShowInSubWindow = options.showInSubWindow;
117 #endif
118     refself_ = this;
119 }
120 
OpenDialog()121 void NativeCustomDialogController::OpenDialog()
122 {
123     if (!builderFunction_) {
124         return;
125     }
126 
127     if (!ownerView_) {
128         return;
129     }
130     auto containerId = ownerView_->GetInstanceId();
131     ContainerScope containerScope(containerId);
132     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
133     auto pipelineContext = PipelineContext::GetCurrentContext();
134     CHECK_NULL_VOID(pipelineContext);
135     auto buildFunc = [builder = builderFunction_, node = frameNode, context = pipelineContext]() {
136         {
137             context->UpdateCurrentActiveNode(node);
138             builder();
139         }
140     };
141 
142     auto cancelTask = ([cancelCallback = cancelFunction_, node = frameNode, context = pipelineContext]() {
143         if (cancelCallback) {
144             context->UpdateCurrentActiveNode(node);
145             cancelCallback();
146         }
147     });
148 
149     auto currentObj = Container::Current();
150     if (currentObj && currentObj->IsScenceBoardWindow() && !dialogProperties_.windowScene.Upgrade()) {
151         dialogProperties_.isScenceBoardDialog = true;
152         auto viewNode = ownerView_->GetViewNode();
153         CHECK_NULL_VOID(viewNode);
154         auto parentCustom = AceType::DynamicCast<NG::CustomNode>(viewNode);
155         CHECK_NULL_VOID(parentCustom);
156         auto parent = parentCustom->GetParent();
157         while (parent && parent->GetTag() != "WindowScene") {
158             parent = parent->GetParent();
159         }
160         if (parent) {
161             dialogProperties_.windowScene = parent;
162         }
163     }
164     dialogProperties_.isSysBlurStyle = false;
165     CustomDialogControllerModel::GetInstance()->SetOpenDialog(dialogProperties_, AccessibilityManager::WeakClaim(this),
166         dialogs_, pending_, isShown_, std::move(cancelTask), std::move(buildFunc), dialogComponent_, customDialog_,
167         dialogOperation_);
168     return;
169 }
170 
CloseDialog()171 void NativeCustomDialogController::CloseDialog()
172 {
173     if (ownerView_ == nullptr) {
174         return;
175     }
176     auto containerId = ownerView_->GetInstanceId();
177     ContainerScope containerScope(containerId);
178 
179     WeakPtr<NG::FrameNode> frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
180     auto cancelTask = ([cancelCallback = cancelFunction_, node = frameNode]() {
181         if (cancelCallback) {
182             auto pipelineContext = PipelineContext::GetCurrentContext();
183             CHECK_NULL_VOID(pipelineContext);
184             pipelineContext->UpdateCurrentActiveNode(node);
185             cancelCallback();
186         }
187     });
188 
189     CustomDialogControllerModel::GetInstance()->SetCloseDialog(dialogProperties_, AccessibilityManager::WeakClaim(this),
190         dialogs_, pending_, isShown_, std::move(cancelTask), dialogComponent_, customDialog_, dialogOperation_);
191 }
192 } // namespace OHOS::Ace::Framework
193 
194 extern "C" {
FfiOHOSAceFrameworkCustomDialogControllerCtor(NativeCustomDialogControllerOptions options)195 int64_t FfiOHOSAceFrameworkCustomDialogControllerCtor(NativeCustomDialogControllerOptions options)
196 {
197     auto controller = FFIData::Create<NativeCustomDialogController>(options);
198     if (controller == nullptr) {
199         return FFI_ERROR_CODE;
200     }
201     return controller->GetID();
202 }
203 
FfiOHOSAceFrameworkCustomDialogControllerSetBuilder(int64_t controllerId,void (* builder)())204 void FfiOHOSAceFrameworkCustomDialogControllerSetBuilder(int64_t controllerId, void (*builder)())
205 {
206     auto nativeController = FFIData::GetData<NativeCustomDialogController>(controllerId);
207     if (nativeController != nullptr) {
208         auto builderFunction = CJLambda::Create(builder);
209         nativeController->SetBuilder(builderFunction);
210     } else {
211         LOGE("CustomDialog: invalid CustomDialogController id");
212     }
213 }
214 
FfiOHOSAceFrameworkCustomDialogControllerBindView(int64_t controllerId,int64_t nativeViewId)215 void FfiOHOSAceFrameworkCustomDialogControllerBindView(int64_t controllerId, int64_t nativeViewId)
216 {
217     auto nativeView = FFIData::GetData<NativeView>(nativeViewId);
218     if (!nativeView) {
219         LOGE("FfiOHOSAceFrameworkCustomDialogControllerBindView: invalid nativeView id");
220         return;
221     }
222 
223     auto nativeController = FFIData::GetData<NativeCustomDialogController>(controllerId);
224     if (nativeController != nullptr) {
225         nativeController->SetView(nativeView);
226     } else {
227         LOGE("FfiOHOSAceFrameworkCustomDialogControllerBindView: invalid CustomDialogController id");
228     }
229 }
230 
FfiOHOSAceFrameworkCustomDialogControllerOpen(int64_t id)231 void FfiOHOSAceFrameworkCustomDialogControllerOpen(int64_t id)
232 {
233     auto nativeController = FFIData::GetData<NativeCustomDialogController>(id);
234     if (nativeController != nullptr) {
235         nativeController->OpenDialog();
236     } else {
237         LOGE("CustomDialog: invalid CustomDialogController id");
238     }
239 }
240 
FfiOHOSAceFrameworkCustomDialogControllerClose(int64_t id)241 void FfiOHOSAceFrameworkCustomDialogControllerClose(int64_t id)
242 {
243     auto nativeController = FFIData::GetData<NativeCustomDialogController>(id);
244     if (nativeController != nullptr) {
245         nativeController->CloseDialog();
246     } else {
247         LOGE("CustomDialog: invalid CustomDialogController id");
248     }
249 }
250 }
251