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_richeditor_ffi.h"
17 
18 #include "cj_lambda.h"
19 #include "bridge/cj_frontend/interfaces/cj_ffi/cj_view_abstract_ffi.h"
20 #include "bridge/cj_frontend/interfaces/cj_ffi/utils.h"
21 #include "core/components_ng/pattern/rich_editor/rich_editor_model.h"
22 #include "core/components_ng/pattern/rich_editor/rich_editor_model_ng.h"
23 
24 using namespace OHOS::Ace;
25 using namespace OHOS::FFI;
26 using namespace OHOS::Ace::Framework;
27 
28 namespace {
29 std::vector<NG::TextResponseType> RESPONSE_TYPES = {
30     NG::TextResponseType::RIGHT_CLICK, NG::TextResponseType::LONG_PRESS
31 };
32 
33 std::vector<NG::TextSpanType> EDITOR_TYPES = {
34     NG::TextSpanType::TEXT, NG::TextSpanType::IMAGE, NG::TextSpanType::MIXED
35 };
36 
37 std::vector<CopyOptions> COPYOPTIONS_TYPES = {
38     CopyOptions::None, CopyOptions::InApp, CopyOptions::Local
39 };
40 }
41 
42 extern "C" {
FfiOHOSAceFrameworkRichEditorCreateWithController(int64_t controllerId)43 void FfiOHOSAceFrameworkRichEditorCreateWithController(int64_t controllerId)
44 {
45     RichEditorModel::GetInstance()->Create();
46     RefPtr<RichEditorBaseControllerBase> controller = RichEditorModel::GetInstance()->GetRichEditorController();
47 
48     auto nativeController = FFIData::GetData<NativeRichEditorController>(controllerId);
49     if (nativeController != nullptr) {
50         nativeController->SetInstanceId(Container::CurrentId());
51         nativeController->SetController(controller);
52     } else {
53         LOGE("RichEditorController is invalid ");
54     }
55 }
56 
FfiOHOSAceFrameworkRichEditorCustomKeyboard(void (* builder)())57 void FfiOHOSAceFrameworkRichEditorCustomKeyboard(void(*builder)())
58 {
59     auto builderFunc = CJLambda::Create(builder);
60     RichEditorModel::GetInstance()->SetCustomKeyboard(std::move(builderFunc));
61 }
62 
FfiOHOSAceFrameworkRichEditorBindSelectionMenu(int32_t spantype,void (* content)(),int32_t responseType,void (* onAppear)(),void (* onDisappear)())63 void FfiOHOSAceFrameworkRichEditorBindSelectionMenu(
64     int32_t spantype, void(*content)(), int32_t responseType, void(*onAppear)(), void(*onDisappear)())
65 {
66     if (!Utils::CheckParamsValid(responseType, RESPONSE_TYPES.size())) {
67         LOGE("BindSelectionMenu error, invalid value for responseType");
68         return;
69     }
70 
71     if (!Utils::CheckParamsValid(spantype, EDITOR_TYPES.size())) {
72         LOGE("BindSelectionMenu error, invalid value for spantype");
73         return;
74     }
75 
76     NG::SelectMenuParam menuParam;
77     menuParam.onAppear = [onAppear = CJLambda::Create(onAppear)](
78         int32_t start, int32_t end) { onAppear(); };
79     menuParam.onDisappear = [onDisappear = CJLambda::Create(onDisappear)]() { onDisappear(); };
80 
81     std::function<void()> buildFunc = CJLambda::Create(content);
82 
83     RichEditorModel::GetInstance()->BindSelectionMenu(
84         EDITOR_TYPES[spantype], RESPONSE_TYPES[responseType], buildFunc, menuParam);
85 }
86 
FfiOHOSAceFrameworkRichEditorCopyOptions(int32_t copyOptions)87 void FfiOHOSAceFrameworkRichEditorCopyOptions(int32_t copyOptions)
88 {
89     if (!Utils::CheckParamsValid(copyOptions, COPYOPTIONS_TYPES.size())) {
90         LOGE("CopyOptions error, invalid value for copyOptions");
91         return;
92     }
93     RichEditorModel::GetInstance()->SetCopyOption(COPYOPTIONS_TYPES[copyOptions]);
94 }
95 
FfiOHOSAceFrameworkRichEditorOnReady(void (* callback)())96 void FfiOHOSAceFrameworkRichEditorOnReady(void(*callback)())
97 {
98     RichEditorModel::GetInstance()->SetOnReady(CJLambda::Create(callback));
99 }
100 
FfiOHOSAceFrameworkRichEditorOnDeleteComplete(void (* callback)())101 void FfiOHOSAceFrameworkRichEditorOnDeleteComplete(void(*callback)())
102 {
103     RichEditorModel::GetInstance()->SetOnDeleteComplete(CJLambda::Create(callback));
104 }
105 
FfiOHOSAceFrameworkRichEditorAboutToIMEInput(bool (* callback)(NativeRichEditorInsertValue))106 void FfiOHOSAceFrameworkRichEditorAboutToIMEInput(bool(*callback)(NativeRichEditorInsertValue))
107 {
108     auto aboutToIMEInputFunc = [cjCallback = CJLambda::Create(callback)](
109         const NG::RichEditorInsertValue& insertValue) -> bool {
110         NativeRichEditorInsertValue result {
111             insertValue.GetInsertOffset(), insertValue.GetInsertValue().c_str()
112         };
113         return cjCallback(result);
114     };
115     RichEditorModel::GetInstance()->SetAboutToIMEInput(std::move(aboutToIMEInputFunc));
116 }
117 
FfiOHOSAceFrameworkRichEditorOnIMEInputComplete(void (* callback)(NativeRichEditorTextSpanResult))118 void FfiOHOSAceFrameworkRichEditorOnIMEInputComplete(void(*callback)(NativeRichEditorTextSpanResult))
119 {
120     auto onIMEInputCompleteFunc = [cjCallback = CJLambda::Create(callback)](
121         const NG::RichEditorAbstractSpanResult& textSpanResult) {
122         NativeRichEditorSpanPosition spanPosition {
123             textSpanResult.GetSpanIndex(),
124             textSpanResult.GetSpanRangeStart(),
125             textSpanResult.GetSpanRangeEnd()
126         };
127 
128         NativeTextDecorationResult decoration {
129             static_cast<int32_t>(textSpanResult.GetTextDecoration()),
130             textSpanResult.GetColor().c_str(),
131         };
132 
133         NativeRichEditorTextStyleResult textStyle {
134             textSpanResult.GetFontColor().c_str(),
135             textSpanResult.GetFontSize(),
136             static_cast<int32_t>(textSpanResult.GetFontStyle()),
137             textSpanResult.GetFontWeight(),
138             textSpanResult.GetFontFamily().c_str(),
139             decoration
140         };
141 
142         NativeRichEditorTextSpanResult result {
143             spanPosition,
144             textSpanResult.GetValue().c_str(),
145             textStyle,
146             textSpanResult.OffsetInSpan(),
147             textSpanResult.OffsetInSpan() + textSpanResult.GetEraseLength()
148         };
149 
150         cjCallback(result);
151     };
152     RichEditorModel::GetInstance()->SetOnIMEInputComplete(std::move(onIMEInputCompleteFunc));
153 }
154 
FfiOHOSAceFrameworkRichEditorOnSelect(void (* callback)(NativeRichEditorSelection))155 void FfiOHOSAceFrameworkRichEditorOnSelect(void(*callback)(NativeRichEditorSelection))
156 {
157     auto onSelectFunc = [cjCallback = CJLambda::Create(callback)](const BaseEventInfo* info) {
158         const auto* eventInfo = TypeInfoHelper::DynamicCast<SelectionInfo>(info);
159         auto selectionInfo = eventInfo->GetSelection();
160 
161         auto selectionStart = selectionInfo.selection[0];
162         auto selectionEnd = selectionInfo.selection[1];
163 
164         const std::list<ResultObject>& spanObjectList = selectionInfo.resultObjects;
165         auto spans = new NativeRichEditorSpanResult[spanObjectList.size()];
166         size_t idx = 0;
167         for (const ResultObject& spanObject : spanObjectList) {
168             NativeRichEditorSpanResult current;
169             if (spanObject.type == SelectSpanType::TYPESPAN) {
170                 current.isText = true;
171                 NativeRichEditorTextSpanResult textResult;
172                 NativeRichEditorController::ParseRichEditorTextSpanResult(spanObject, textResult);
173                 current.textResult = textResult;
174             } else {
175                 current.isText = false;
176                 NativeRichEditorImageSpanResult imageResult;
177                 NativeRichEditorController::ParseRichEditorImageSpanResult(spanObject, imageResult);
178                 current.imageResult = imageResult;
179             }
180             spans[idx] = current;
181             idx ++;
182         }
183         NativeRichEditorSelection result;
184         result.selectionStart = selectionStart;
185         result.selectionEnd = selectionEnd;
186         result.spans = spans;
187         result.spanSize = static_cast<int64_t>(spanObjectList.size());
188 
189         cjCallback(result);
190         delete[] spans;
191     };
192     RichEditorModel::GetInstance()->SetOnSelect(std::move(onSelectFunc));
193 }
194 
FfiOHOSAceFrameworkRichEditorAboutToDelete(bool (* callback)(NativeRichEditorDeleteValue))195 void FfiOHOSAceFrameworkRichEditorAboutToDelete(bool(*callback)(NativeRichEditorDeleteValue))
196 {
197     auto aboutToDeleteFunc = [cjCallback = CJLambda::Create(callback)](
198             const NG::RichEditorDeleteValue& deleteValue) -> bool {
199         const std::list<NG::RichEditorAbstractSpanResult>& deleteSpans = deleteValue.GetRichEditorDeleteSpans();
200         auto spans = new NativeRichEditorSpanResult[deleteSpans.size()];
201         size_t idx = 0;
202         for (const NG::RichEditorAbstractSpanResult& spanObject : deleteSpans) {
203             NativeRichEditorSpanResult current;
204             if (spanObject.GetType() == NG::SpanResultType::TEXT) {
205                 current.isText = true;
206                 NativeRichEditorTextSpanResult textResult;
207                 NativeRichEditorController::ParseRichEditorAbstractTextSpanResult(spanObject, textResult);
208                 current.textResult = textResult;
209             } else {
210                 current.isText = false;
211                 NativeRichEditorImageSpanResult imageResult;
212                 NativeRichEditorController::ParseRichEditorAbstractImageSpanResult(spanObject, imageResult);
213                 current.imageResult = imageResult;
214             }
215             spans[idx] = current;
216             idx ++;
217         }
218         NativeRichEditorDeleteValue result;
219         result.offset = deleteValue.GetOffset();
220         result.direction = static_cast<int32_t>(deleteValue.GetRichEditorDeleteDirection());
221         result.length = deleteValue.GetLength();
222         result.richEditorDeleteSpans = spans;
223         result.spanSize = static_cast<int64_t>(deleteSpans.size());
224 
225         auto res = cjCallback(result);
226         delete[] spans;
227         return res;
228     };
229     RichEditorModel::GetInstance()->SetAboutToDelete(std::move(aboutToDeleteFunc));
230 }
231 
FfiOHOSAceFrameworkRichEditorOnPaste(void (* callback)(int64_t))232 void FfiOHOSAceFrameworkRichEditorOnPaste(void(*callback)(int64_t))
233 {
234     auto onPast = [cjCallback = CJLambda::Create(callback)](NG::TextCommonEvent& info) {
235         auto nativePasteEvent = FFIData::Create<NativePasteEvent>(&info);
236         if (nativePasteEvent == nullptr) {
237             return;
238         }
239         cjCallback(nativePasteEvent->GetID());
240     };
241     RichEditorModel::GetInstance()->SetOnPaste(std::move(onPast));
242 }
243 
FfiOHOSAceFrameworkRichEditorPreventDefault(int64_t id)244 void FfiOHOSAceFrameworkRichEditorPreventDefault(int64_t id)
245 {
246     auto nativePasteEvent = FFIData::GetData<NativePasteEvent>(id);
247     nativePasteEvent->PreventDefault();
248 }
249 
FfiOHOSAceFrameworkRichEditorOnDidChange(void (* callback)(CJTextRange rangeBefore,CJTextRange rangeAfter))250 void FfiOHOSAceFrameworkRichEditorOnDidChange(void(*callback)(CJTextRange rangeBefore, CJTextRange rangeAfter))
251 {
252     auto onDidChange = [cjCallback = CJLambda::Create(callback)](const NG::RichEditorChangeValue& changeValue) {
253         const auto& rangeBefore = changeValue.GetRangeBefore();
254         const auto& rangeAfter = changeValue.GetRangeAfter();
255         CJTextRange cjRangeBefore = { rangeBefore.start, rangeBefore.end };
256         CJTextRange cjRangeAfter = { rangeAfter.start, rangeAfter.end };
257 
258         cjCallback(cjRangeBefore, cjRangeAfter);
259     };
260     RichEditorModel::GetInstance()->SetOnDidChange(std::move(onDidChange));
261 }
262 }
263