1 /*
2 * Copyright (c) 2025 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/arkts_frontend/ani_graphics_module.h"
17
18 #include <ani.h>
19
20 // #if !defined(PREVIEW)
21 // #include "canvas_ani/ani_canvas.h"
22 // #endif
23
24 #include "core/components_ng/pattern/render_node/render_node_pattern.h"
25 #include "core/interfaces/native/implementation/render_node_peer_impl.h"
26 #include "core/pipeline/pipeline_base.h"
27
28 namespace OHOS::Ace::Framework {
29 namespace {
CreateSizeObject(ani_env * env,const NG::DrawingContext & context)30 ani_object CreateSizeObject(ani_env* env, const NG::DrawingContext& context)
31 {
32 ani_status status;
33 ani_class sizeClass;
34 if ((status = env->FindClass("Larkui/Graphics/SizeInternal;", &sizeClass)) != ANI_OK) {
35 LOGE("FindClass Size failed, %{public}d", status);
36 return nullptr;
37 }
38 ani_method sizeCtor;
39 if ((status = env->Class_FindMethod(sizeClass, "<ctor>", "DD:V", &sizeCtor)) != ANI_OK) {
40 LOGE("Class_FindMethod sizeClass ctor failed, %{public}d", status);
41 return nullptr;
42 }
43 ani_object sizeObject;
44 ani_float width = PipelineBase::Px2VpWithCurrentDensity(context.height);
45 ani_float height = PipelineBase::Px2VpWithCurrentDensity(context.width);
46 if ((status = env->Object_New(sizeClass, sizeCtor, &sizeObject, width, height)) != ANI_OK) {
47 LOGE("New Size object failed, %{public}d", status);
48 return nullptr;
49 }
50 return sizeObject;
51 }
52
CreateSizeInPixelObject(ani_env * env,const NG::DrawingContext & context)53 ani_object CreateSizeInPixelObject(ani_env* env, const NG::DrawingContext& context)
54 {
55 ani_status status;
56 ani_class sizeInPixelClass;
57 if ((status = env->FindClass("Larkui/Graphics/SizeInternal;", &sizeInPixelClass)) != ANI_OK) {
58 LOGE("FindClass Size failed, %{public}d", status);
59 return nullptr;
60 }
61 ani_method sizeInPixelCtor;
62 if ((status = env->Class_FindMethod(sizeInPixelClass, "<ctor>", "DD:V", &sizeInPixelCtor)) != ANI_OK) {
63 LOGE("Class_FindMethod sizeInPixelClass ctor failed, %{public}d", status);
64 return nullptr;
65 }
66 ani_object sizeInPixelObject;
67 ani_float widthInPixel = context.width;
68 ani_float heightInPixel = context.height;
69 if ((status = env->Object_New(
70 sizeInPixelClass, sizeInPixelCtor, &sizeInPixelObject, widthInPixel, heightInPixel)) != ANI_OK) {
71 LOGE("New SizeInPixel object failed, %{public}d", status);
72 return nullptr;
73 }
74 return sizeInPixelObject;
75 }
76 } // namespace
77
CreateDrawingContext(ani_env * env,const NG::DrawingContext & context)78 ani_object AniGraphicsModule::CreateDrawingContext(ani_env* env, const NG::DrawingContext& context)
79 {
80 ani_status status;
81 ani_object result = nullptr;
82
83 // DrawContext object
84 ani_class drawContextClass;
85 if ((status = env->FindClass("Larkui/Graphics/DrawContext;", &drawContextClass)) != ANI_OK) {
86 LOGE("FindClass DrawContext failed, %{public}d", status);
87 return nullptr;
88 }
89 ani_method drawContextCtor;
90 if ((status = env->Class_FindMethod(drawContextClass, "<ctor>", ":V", &drawContextCtor)) != ANI_OK) {
91 LOGE("Class_FindMethod drawContextClass ctor failed, %{public}d", status);
92 return nullptr;
93 }
94 if ((status = env->Object_New(drawContextClass, drawContextCtor, &result)) != ANI_OK) {
95 LOGE("New DrawContext object failed, %{public}d", status);
96 return nullptr;
97 }
98
99 // Size object
100 ani_object sizeObject = CreateSizeObject(env, context);
101 env->Object_SetPropertyByName_Ref(result, "size_", (ani_ref)sizeObject);
102
103 // sizeInPixel Object
104 ani_object sizeInPixelObject = CreateSizeInPixelObject(env, context);
105 env->Object_SetPropertyByName_Ref(result, "sizeInPixel_", (ani_ref)sizeInPixelObject);
106
107 // canvas Object
108 #if !defined(PREVIEW)
109 // ani_object aniCanvas = OHOS::Rosen::Drawing::AniCanvas::CreateAniCanvas(env, &context.canvas);
110 // if (!aniCanvas) {
111 // LOGE("Create AniCanvas failed !");
112 // }
113 // env->Object_SetPropertyByName_Ref(result, "canvas_", (ani_ref)aniCanvas);
114 #endif
115
116 return result;
117 }
118
SetDrawCallback(ani_env * env,ani_long ptr,ani_fn_object fnObj)119 void AniGraphicsModule::SetDrawCallback(ani_env* env, ani_long ptr, ani_fn_object fnObj)
120 {
121 if (fnObj == nullptr) {
122 LOGE("Draw callback is undefined.");
123 return;
124 }
125 ani_ref fnObjGlobalRef = nullptr;
126 env->GlobalReference_Create(reinterpret_cast<ani_ref>(fnObj), &fnObjGlobalRef);
127 auto drawCallbackFunc = [env, fnObjGlobalRef](const NG::DrawingContext& context) -> void {
128 auto drawingContext = CreateDrawingContext(env, context);
129 if (!drawingContext) {
130 LOGW("Create drawing context failed !");
131 return;
132 }
133 std::vector<ani_ref> params;
134 params.emplace_back((ani_ref)drawingContext);
135 ani_ref fnReturnVal;
136 env->FunctionalObject_Call(
137 reinterpret_cast<ani_fn_object>(fnObjGlobalRef), params.size(), params.data(), &fnReturnVal);
138 };
139
140 auto* renderNodePeer = reinterpret_cast<RenderNodePeer*>(ptr);
141 CHECK_NULL_VOID(renderNodePeer);
142 auto renderNode = renderNodePeer->GetFrameNode();
143 auto pattern = renderNode->GetPattern<NG::RenderNodePattern>();
144 if (pattern) {
145 pattern->SetDrawCallback(drawCallbackFunc);
146 }
147 }
148
Invalidate(ani_env * env,ani_long ptr)149 void AniGraphicsModule::Invalidate(ani_env* env, ani_long ptr)
150 {
151 auto* frameNode = reinterpret_cast<NG::FrameNode*>(ptr);
152 CHECK_NULL_VOID(frameNode);
153 const auto& extensionHandler = frameNode->GetExtensionHandler();
154 if (extensionHandler) {
155 extensionHandler->InvalidateRender();
156 } else {
157 frameNode->MarkDirtyNode(NG::PROPERTY_UPDATE_RENDER);
158 }
159 }
160
SetDrawModifier(ani_env * env,ani_long ptr,ani_object drawModifierObj)161 void AniGraphicsModule::SetDrawModifier(ani_env* env, ani_long ptr, ani_object drawModifierObj)
162 {
163 if (drawModifierObj == nullptr) {
164 // drawModifierObj should not be nullptr;
165 LOGF_ABORT("DrawModifier is undefined.");
166 }
167 ani_ref modifier;
168 env->GlobalReference_Create(reinterpret_cast<ani_ref>(drawModifierObj), &modifier);
169 auto drawBehindFunc = [env, object = modifier](const NG::DrawingContext& context) {
170 auto drawingContext = Framework::AniGraphicsModule::CreateDrawingContext(env, context);
171 if (!drawingContext) {
172 return;
173 }
174 env->Object_CallMethodByName_Void(
175 reinterpret_cast<ani_fn_object>(object), "drawBehind", "Larkui/Graphics/DrawContext;:V", drawingContext);
176 };
177 auto contentModifier = [env, object = modifier](const NG::DrawingContext& context) {
178 auto drawingContext = Framework::AniGraphicsModule::CreateDrawingContext(env, context);
179 if (!drawingContext) {
180 return;
181 }
182 env->Object_CallMethodByName_Void(
183 reinterpret_cast<ani_fn_object>(object), "drawContent", "Larkui/Graphics/DrawContext;:V", drawingContext);
184 };
185 auto frontModifier = [env, object = modifier](const NG::DrawingContext& context) {
186 auto drawingContext = Framework::AniGraphicsModule::CreateDrawingContext(env, context);
187 if (!drawingContext) {
188 return;
189 }
190 env->Object_CallMethodByName_Void(
191 reinterpret_cast<ani_fn_object>(object), "drawFront", "Larkui/Graphics/DrawContext;:V", drawingContext);
192 };
193 auto* frameNode = reinterpret_cast<NG::FrameNode*>(ptr);
194 CHECK_NULL_VOID(frameNode && frameNode->IsSupportDrawModifier());
195 RefPtr<NG::DrawModifier> drawModifier = AceType::MakeRefPtr<NG::DrawModifier>();
196 drawModifier->drawBehindFunc = drawBehindFunc;
197 drawModifier->drawContentFunc = contentModifier;
198 drawModifier->drawFrontFunc = frontModifier;
199 frameNode->SetDrawModifier(drawModifier);
200 if (frameNode) {
201 const auto& extensionHandler = frameNode->GetExtensionHandler();
202 if (extensionHandler) {
203 extensionHandler->InvalidateRender();
204 } else {
205 frameNode->MarkDirtyNode(NG::PROPERTY_UPDATE_RENDER);
206 }
207 }
208 }
209 } // namespace OHOS::Ace::Framework
210